summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--cmd/podman/common/create.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.go53
-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.go6
-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.go10
-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/healthcheck/run.go13
-rw-r--r--cmd/podman/images/build.go11
-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/images/tag.go22
-rw-r--r--cmd/podman/images/untag.go22
-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/inspect.go13
-rw-r--r--cmd/podman/manifest/manifest.go9
-rw-r--r--cmd/podman/manifest/push.go1
-rw-r--r--cmd/podman/manifest/remove.go13
-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/config_tunnel.go7
-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/renumber.go11
-rw-r--r--cmd/podman/system/system.go9
-rw-r--r--cmd/podman/system/unshare.go9
-rw-r--r--cmd/podman/validate/args.go116
-rw-r--r--cmd/podman/validate/latest.go15
-rw-r--r--cmd/podman/volumes/volume.go9
-rw-r--r--contrib/remote/containers.conf11
-rw-r--r--docs/source/markdown/podman-auto-update.1.md2
-rw-r--r--docs/source/markdown/podman-container-exists.1.md2
-rw-r--r--docs/source/markdown/podman-create.1.md7
-rw-r--r--docs/source/markdown/podman-healthcheck-run.1.md2
-rw-r--r--docs/source/markdown/podman-image-exists.1.md2
-rw-r--r--docs/source/markdown/podman-manifest-add.1.md2
-rw-r--r--docs/source/markdown/podman-manifest-annotate.1.md2
-rw-r--r--docs/source/markdown/podman-manifest-push.1.md2
-rw-r--r--docs/source/markdown/podman-mount.1.md4
-rw-r--r--docs/source/markdown/podman-network-inspect.1.md2
-rw-r--r--docs/source/markdown/podman-network-rm.1.md2
-rw-r--r--docs/source/markdown/podman-pod-prune.1.md2
-rw-r--r--docs/source/markdown/podman-rmi.1.md4
-rw-r--r--docs/source/markdown/podman-run.1.md13
-rw-r--r--docs/source/markdown/podman-system-migrate.1.md2
-rw-r--r--docs/source/markdown/podman-system-reset.1.md2
-rw-r--r--docs/source/markdown/podman-system-service.1.md4
-rw-r--r--docs/source/markdown/podman-umount.1.md8
-rw-r--r--docs/source/markdown/podman-unshare.1.md2
-rw-r--r--docs/source/markdown/podman-untag.1.md4
-rw-r--r--go.mod2
-rw-r--r--go.sum2
-rwxr-xr-xhack/man-page-checker72
-rw-r--r--libpod/container.go22
-rw-r--r--libpod/container_internal_linux.go12
-rw-r--r--libpod/container_validate.go4
-rw-r--r--libpod/oci_conmon.go7
-rw-r--r--libpod/oci_conmon_linux.go10
-rw-r--r--libpod/options.go2
-rw-r--r--libpod/runtime_ctr.go4
-rw-r--r--libpod/volume.go12
-rw-r--r--pkg/api/handlers/compat/networks.go2
-rw-r--r--pkg/api/server/server.go4
-rw-r--r--pkg/domain/filters/volumes.go23
-rw-r--r--pkg/domain/infra/abi/system.go2
-rw-r--r--pkg/ps/ps.go8
-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/systemd/generate/containers.go2
-rw-r--r--pkg/systemd/generate/containers_test.go2
-rw-r--r--pkg/terminal/console_unix.go8
-rw-r--r--pkg/terminal/console_windows.go37
-rw-r--r--test/e2e/inspect_test.go26
-rw-r--r--test/e2e/ps_test.go17
-rw-r--r--test/e2e/run_networking_test.go24
-rw-r--r--test/e2e/volume_ls_test.go27
-rw-r--r--test/python/dockerpy/README.md40
-rw-r--r--test/python/dockerpy/__init__.py (renamed from test/test_dockerpy/__init__.py)0
-rw-r--r--test/python/dockerpy/tests/__init__.py0
-rw-r--r--test/python/dockerpy/tests/common.py105
-rw-r--r--test/python/dockerpy/tests/constant.py13
-rw-r--r--test/python/dockerpy/tests/test_containers.py (renamed from test/test_dockerpy/test_containers.py)43
-rw-r--r--test/python/dockerpy/tests/test_images.py (renamed from test/test_dockerpy/test_images.py)84
-rw-r--r--test/python/dockerpy/tests/test_info_version.py (renamed from test/test_dockerpy/test_info_version.py)12
-rw-r--r--test/system/015-help.bats18
-rw-r--r--test/system/030-run.bats41
-rw-r--r--test/system/200-pod.bats41
-rw-r--r--test/system/250-systemd.bats8
-rw-r--r--test/system/410-selinux.bats19
-rw-r--r--test/test_dockerpy/README.md30
-rw-r--r--test/test_dockerpy/common.py85
-rw-r--r--test/test_dockerpy/constant.py13
-rw-r--r--utils/utils_supported.go122
-rw-r--r--utils/utils_windows.go12
-rw-r--r--vendor/github.com/containers/common/pkg/apparmor/apparmor.go6
-rw-r--r--vendor/github.com/containers/common/pkg/apparmor/apparmor_linux.go9
-rw-r--r--vendor/github.com/containers/common/pkg/config/config.go6
-rw-r--r--vendor/github.com/containers/common/version/version.go4
-rw-r--r--vendor/modules.txt3
146 files changed, 1519 insertions, 837 deletions
diff --git a/Makefile b/Makefile
index 55b42c431..5c813dac5 100644
--- a/Makefile
+++ b/Makefile
@@ -478,6 +478,7 @@ podman-remote-release-%.zip:
cp release.txt "$(TMPDIR)/"
cp ./bin/podman-remote-$*$(BINSFX) "$(TMPDIR)/$(SUBDIR)/podman$(BINSFX)"
cp -r ./docs/build/remote/$* "$(TMPDIR)/$(SUBDIR)/docs/"
+ cp ./contrib/remote/containers.conf "$(TMPDIR)/$(SUBDIR)/"
cd "$(TMPDIR)/$(SUBDIR)" && \
zip --recurse-paths "$(CURDIR)/$@" "./release.txt" "./"
-rm -rf "$(TMPDIR)"
diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go
index fbb7f449e..ec3251ae1 100644
--- a/cmd/podman/common/create.go
+++ b/cmd/podman/common/create.go
@@ -57,7 +57,7 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
createFlags.StringVar(
&cf.CGroupsMode,
"cgroups", containerConfig.Cgroups(),
- `control container cgroup configuration ("enabled"|"disabled"|"no-conmon")`,
+ `control container cgroup configuration ("enabled"|"disabled"|"no-conmon"|"split")`,
)
createFlags.StringVar(
&cf.CGroupParent,
diff --git a/cmd/podman/common/util.go b/cmd/podman/common/util.go
index ce323a4ba..6c8c22147 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 9ef9d79f0..cb3b1bd3c 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 c4723af21..fa1bc899b 100644
--- a/cmd/podman/containers/checkpoint.go
+++ b/cmd/podman/containers/checkpoint.go
@@ -4,9 +4,9 @@ import (
"context"
"fmt"
- "github.com/containers/libpod/cmd/podman/parse"
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/cmd/podman/utils"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/containers/libpod/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 619031208..7e9e7e9ef 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/cmd/podman/parse"
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/cmd/podman/utils"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/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 45ce00c86..60e9aa815 100644
--- a/cmd/podman/containers/create.go
+++ b/cmd/podman/containers/create.go
@@ -6,11 +6,12 @@ import (
"os"
"strings"
- "github.com/containers/libpod/libpod/define"
-
"github.com/containers/common/pkg/config"
+ "github.com/containers/image/v5/storage"
+ "github.com/containers/image/v5/transports/alltransports"
"github.com/containers/libpod/cmd/podman/common"
"github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/containers/libpod/pkg/errorhandling"
"github.com/containers/libpod/pkg/specgen"
@@ -57,6 +58,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")
@@ -108,12 +110,15 @@ func create(cmd *cobra.Command, args []string) error {
return err
}
+ imageName := args[0]
if !cliVals.RootFS {
- if err := pullImage(args[0]); err != nil {
+ name, err := pullImage(args[0])
+ if err != nil {
return err
}
+ imageName = name
}
- s := specgen.NewSpecGenerator(args[0], cliVals.RootFS)
+ s := specgen.NewSpecGenerator(imageName, cliVals.RootFS)
if err := common.FillOutSpecGen(s, &cliVals, args); err != nil {
return err
}
@@ -205,36 +210,54 @@ func createInit(c *cobra.Command) error {
cliVals.Env = env
}
+ if c.Flag("cgroups").Changed && cliVals.CGroupsMode == "split" && registry.IsRemote() {
+ return errors.Errorf("the option --cgroups=%q is not supported in remote mode", cliVals.CGroupsMode)
+ }
+
// Docker-compatibility: the "-h" flag for run/create is reserved for
// the hostname (see https://github.com/containers/libpod/issues/1367).
return nil
}
-func pullImage(imageName string) error {
- br, err := registry.ImageEngine().Exists(registry.GetContext(), imageName)
- if err != nil {
- return err
- }
+func pullImage(imageName string) (string, error) {
pullPolicy, err := config.ValidatePullPolicy(cliVals.Pull)
if err != nil {
- return err
+ return "", err
}
- if !br.Value || pullPolicy == config.PullImageAlways {
+
+ // Check if the image is missing and hence if we need to pull it.
+ imageMissing := true
+ imageRef, err := alltransports.ParseImageName(imageName)
+ switch {
+ case err != nil:
+ // Assume we specified a local image withouth the explicit storage transport.
+ fallthrough
+
+ case imageRef.Transport().Name() == storage.Transport.Name():
+ br, err := registry.ImageEngine().Exists(registry.GetContext(), imageName)
+ if err != nil {
+ return "", err
+ }
+ imageMissing = !br.Value
+ }
+
+ if imageMissing || pullPolicy == config.PullImageAlways {
if pullPolicy == config.PullImageNever {
- return errors.Wrapf(define.ErrNoSuchImage, "unable to find a name and tag match for %s in repotags", imageName)
+ return "", errors.Wrapf(define.ErrNoSuchImage, "unable to find a name and tag match for %s in repotags", imageName)
}
- _, pullErr := registry.ImageEngine().Pull(registry.GetContext(), imageName, entities.ImagePullOptions{
+ pullReport, pullErr := registry.ImageEngine().Pull(registry.GetContext(), imageName, entities.ImagePullOptions{
Authfile: cliVals.Authfile,
Quiet: cliVals.Quiet,
OverrideArch: cliVals.OverrideArch,
OverrideOS: cliVals.OverrideOS,
})
if pullErr != nil {
- return pullErr
+ return "", pullErr
}
+ imageName = pullReport.Images[0]
}
- return nil
+ return imageName, nil
}
func openCidFile(cidfile string) (*os.File, error) {
diff --git a/cmd/podman/containers/diff.go b/cmd/podman/containers/diff.go
index 33b1c1126..812a61a78 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 ce48af618..3c713a7c4 100644
--- a/cmd/podman/containers/exec.go
+++ b/cmd/podman/containers/exec.go
@@ -6,6 +6,7 @@ import (
"os"
"github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/domain/entities"
envLib "github.com/containers/libpod/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 417f170c3..6ae52986c 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/cmd/podman/parse"
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/cmd/podman/utils"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/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 e49fcc2e0..1798fa99c 100644
--- a/cmd/podman/containers/inspect.go
+++ b/cmd/podman/containers/inspect.go
@@ -3,6 +3,7 @@ package containers
import (
"github.com/containers/libpod/cmd/podman/inspect"
"github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/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 ef85aad7d..5289a2a0e 100644
--- a/cmd/podman/containers/kill.go
+++ b/cmd/podman/containers/kill.go
@@ -5,9 +5,9 @@ import (
"errors"
"fmt"
- "github.com/containers/libpod/cmd/podman/parse"
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/cmd/podman/utils"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/containers/libpod/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 c200a49aa..6aadbcc75 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 de5234044..351a055df 100644
--- a/cmd/podman/containers/logs.go
+++ b/cmd/podman/containers/logs.go
@@ -4,6 +4,7 @@ import (
"os"
"github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/containers/libpod/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 5c73cceaa..ddde0cc9f 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/cmd/podman/parse"
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/cmd/podman/utils"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/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 b932c4539..19d97f196 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 115adc2a7..3ad6c507b 100644
--- a/cmd/podman/containers/port.go
+++ b/cmd/podman/containers/port.go
@@ -5,8 +5,8 @@ import (
"strconv"
"strings"
- "github.com/containers/libpod/cmd/podman/parse"
"github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/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 5d3c9263e..d10cda609 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.
diff --git a/cmd/podman/containers/restart.go b/cmd/podman/containers/restart.go
index 1a9d7f6c7..83d6a13ca 100644
--- a/cmd/podman/containers/restart.go
+++ b/cmd/podman/containers/restart.go
@@ -4,9 +4,9 @@ import (
"context"
"fmt"
- "github.com/containers/libpod/cmd/podman/parse"
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/cmd/podman/utils"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/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 3bc17206a..a5e328e8e 100644
--- a/cmd/podman/containers/restore.go
+++ b/cmd/podman/containers/restore.go
@@ -4,9 +4,9 @@ import (
"context"
"fmt"
- "github.com/containers/libpod/cmd/podman/parse"
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/cmd/podman/utils"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/containers/libpod/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 22d6d59b4..bb7bca081 100644
--- a/cmd/podman/containers/rm.go
+++ b/cmd/podman/containers/rm.go
@@ -5,9 +5,9 @@ import (
"fmt"
"strings"
- "github.com/containers/libpod/cmd/podman/parse"
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/cmd/podman/utils"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/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 cb307c38f..dda22e539 100644
--- a/cmd/podman/containers/run.go
+++ b/cmd/podman/containers/run.go
@@ -62,6 +62,7 @@ func runFlags(flags *pflag.FlagSet) {
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")
flags.UintVar(&runOpts.PreserveFDs, "preserve-fds", 0, "Pass a number of additional file descriptors into the container")
+
if registry.IsRemote() {
_ = flags.MarkHidden("authfile")
_ = flags.MarkHidden("env-host")
@@ -125,10 +126,13 @@ func run(cmd *cobra.Command, args []string) error {
return err
}
+ imageName := args[0]
if !cliVals.RootFS {
- if err := pullImage(args[0]); err != nil {
+ name, err := pullImage(args[0])
+ if err != nil {
return err
}
+ imageName = name
}
if cliVals.Replace {
@@ -166,7 +170,7 @@ func run(cmd *cobra.Command, args []string) error {
runOpts.Detach = cliVals.Detach
runOpts.DetachKeys = cliVals.DetachKeys
cliVals.PreserveFDs = runOpts.PreserveFDs
- s := specgen.NewSpecGenerator(args[0], cliVals.RootFS)
+ s := specgen.NewSpecGenerator(imageName, cliVals.RootFS)
if err := common.FillOutSpecGen(s, &cliVals, args); err != nil {
return err
}
@@ -196,7 +200,7 @@ func run(cmd *cobra.Command, args []string) error {
return nil
}
if runRmi {
- _, rmErrors := registry.ImageEngine().Remove(registry.GetContext(), []string{args[0]}, entities.ImageRemoveOptions{})
+ _, rmErrors := registry.ImageEngine().Remove(registry.GetContext(), []string{imageName}, entities.ImageRemoveOptions{})
if len(rmErrors) > 0 {
logrus.Errorf("%s", errors.Wrapf(errorhandling.JoinErrors(rmErrors), "failed removing image"))
}
diff --git a/cmd/podman/containers/start.go b/cmd/podman/containers/start.go
index 751fec65f..05e1c38ef 100644
--- a/cmd/podman/containers/start.go
+++ b/cmd/podman/containers/start.go
@@ -6,6 +6,7 @@ import (
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/cmd/podman/utils"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/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 260cbd25d..3da68949a 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/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/cgroups"
"github.com/containers/libpod/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 0f2a91af0..b525fc97a 100644
--- a/cmd/podman/containers/stop.go
+++ b/cmd/podman/containers/stop.go
@@ -4,9 +4,9 @@ import (
"context"
"fmt"
- "github.com/containers/libpod/cmd/podman/parse"
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/cmd/podman/utils"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/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 afab12a14..cd01046cc 100644
--- a/cmd/podman/containers/top.go
+++ b/cmd/podman/containers/top.go
@@ -8,6 +8,7 @@ import (
"text/tabwriter"
"github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/containers/libpod/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 c8e551e28..c061a6df3 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/cmd/podman/parse"
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/cmd/podman/utils"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/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 115bb3eea..be5cfce9a 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 d635ea57a..eaf6abf02 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 7803c0c78..a13e50903 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 f48701624..15ed47d39 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/healthcheck/run.go b/cmd/podman/healthcheck/run.go
index 5612910cb..17ddf17b6 100644
--- a/cmd/podman/healthcheck/run.go
+++ b/cmd/podman/healthcheck/run.go
@@ -12,12 +12,13 @@ import (
var (
healthcheckRunDescription = "run the health check of a container"
healthcheckrunCommand = &cobra.Command{
- Use: "run [flags] CONTAINER",
- Short: "run the health check of a container",
- Long: healthcheckRunDescription,
- Example: `podman healthcheck run mywebapp`,
- RunE: run,
- Args: cobra.ExactArgs(1),
+ Use: "run CONTAINER",
+ Short: "run the health check of a container",
+ Long: healthcheckRunDescription,
+ Example: `podman healthcheck run mywebapp`,
+ RunE: run,
+ Args: cobra.ExactArgs(1),
+ DisableFlagsInUseLine: true,
}
)
diff --git a/cmd/podman/images/build.go b/cmd/podman/images/build.go
index dfde896a1..eefc488d3 100644
--- a/cmd/podman/images/build.go
+++ b/cmd/podman/images/build.go
@@ -40,12 +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,
- Args: cobra.MaximumNArgs(1),
+ 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 c24f98369..53165543c 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 ebef126c0..2d1974d5c 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 ccac7e3fe..d7756433b 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/images/tag.go b/cmd/podman/images/tag.go
index dae3416c4..859489552 100644
--- a/cmd/podman/images/tag.go
+++ b/cmd/podman/images/tag.go
@@ -9,22 +9,24 @@ import (
var (
tagDescription = "Adds one or more additional names to locally-stored image."
tagCommand = &cobra.Command{
- Use: "tag [flags] IMAGE TARGET_NAME [TARGET_NAME...]",
- Short: "Add an additional name to a local image",
- Long: tagDescription,
- RunE: tag,
- Args: cobra.MinimumNArgs(2),
+ Use: "tag IMAGE TARGET_NAME [TARGET_NAME...]",
+ Short: "Add an additional name to a local image",
+ Long: tagDescription,
+ RunE: tag,
+ Args: cobra.MinimumNArgs(2),
+ DisableFlagsInUseLine: true,
Example: `podman tag 0e3bbc2 fedora:latest
podman tag imageID:latest myNewImage:newTag
podman tag httpd myregistryhost:5000/fedora/httpd:v2`,
}
imageTagCommand = &cobra.Command{
- Args: tagCommand.Args,
- Use: tagCommand.Use,
- Short: tagCommand.Short,
- Long: tagCommand.Long,
- RunE: tagCommand.RunE,
+ Args: tagCommand.Args,
+ DisableFlagsInUseLine: true,
+ Use: tagCommand.Use,
+ Short: tagCommand.Short,
+ Long: tagCommand.Long,
+ RunE: tagCommand.RunE,
Example: `podman image tag 0e3bbc2 fedora:latest
podman image tag imageID:latest myNewImage:newTag
podman image tag httpd myregistryhost:5000/fedora/httpd:v2`,
diff --git a/cmd/podman/images/untag.go b/cmd/podman/images/untag.go
index 266a3f115..5d1274895 100644
--- a/cmd/podman/images/untag.go
+++ b/cmd/podman/images/untag.go
@@ -8,22 +8,24 @@ import (
var (
untagCommand = &cobra.Command{
- Use: "untag [flags] IMAGE [NAME...]",
- Short: "Remove a name from a local image",
- Long: "Removes one or more names from a locally-stored image.",
- RunE: untag,
- Args: cobra.MinimumNArgs(1),
+ Use: "untag IMAGE [NAME...]",
+ Short: "Remove a name from a local image",
+ Long: "Removes one or more names from a locally-stored image.",
+ RunE: untag,
+ Args: cobra.MinimumNArgs(1),
+ DisableFlagsInUseLine: true,
Example: `podman untag 0e3bbc2
podman untag imageID:latest otherImageName:latest
podman untag httpd myregistryhost:5000/fedora/httpd:v2`,
}
imageUntagCommand = &cobra.Command{
- Args: untagCommand.Args,
- Use: untagCommand.Use,
- Short: untagCommand.Short,
- Long: untagCommand.Long,
- RunE: untagCommand.RunE,
+ Args: untagCommand.Args,
+ DisableFlagsInUseLine: true,
+ Use: untagCommand.Use,
+ Short: untagCommand.Short,
+ Long: untagCommand.Long,
+ RunE: untagCommand.RunE,
Example: `podman image untag 0e3bbc2
podman image untag imageID:latest otherImageName:latest
podman image untag httpd myregistryhost:5000/fedora/httpd:v2`,
diff --git a/cmd/podman/inspect.go b/cmd/podman/inspect.go
index 6c4607d88..12e11d0f5 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 d80bbffdd..1c1e68d6f 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/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/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 f502e7a67..636538131 100644
--- a/cmd/podman/main.go
+++ b/cmd/podman/main.go
@@ -16,7 +16,9 @@ import (
_ "github.com/containers/libpod/cmd/podman/system"
_ "github.com/containers/libpod/cmd/podman/volumes"
"github.com/containers/libpod/pkg/rootless"
+ "github.com/containers/libpod/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/inspect.go b/cmd/podman/manifest/inspect.go
index 5112aa5b2..861f4be4f 100644
--- a/cmd/podman/manifest/inspect.go
+++ b/cmd/podman/manifest/inspect.go
@@ -12,12 +12,13 @@ import (
var (
inspectCmd = &cobra.Command{
- Use: "inspect [flags] IMAGE",
- Short: "Display the contents of a manifest list or image index",
- Long: "Display the contents of a manifest list or image index.",
- RunE: inspect,
- Example: "podman manifest inspect localhost/list",
- Args: cobra.ExactArgs(1),
+ Use: "inspect IMAGE",
+ Short: "Display the contents of a manifest list or image index",
+ Long: "Display the contents of a manifest list or image index.",
+ RunE: inspect,
+ Example: "podman manifest inspect localhost/list",
+ Args: cobra.ExactArgs(1),
+ DisableFlagsInUseLine: true,
}
)
diff --git a/cmd/podman/manifest/manifest.go b/cmd/podman/manifest/manifest.go
index d7f042a56..26a516ec8 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 a2e68aff1..e3073faea 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/manifest/remove.go b/cmd/podman/manifest/remove.go
index 4d345efc0..815a3f0a8 100644
--- a/cmd/podman/manifest/remove.go
+++ b/cmd/podman/manifest/remove.go
@@ -12,12 +12,13 @@ import (
var (
removeCmd = &cobra.Command{
- Use: "remove [flags] LIST IMAGE",
- Short: "Remove an entry from a manifest list or image index",
- Long: "Removes an image from a manifest list or image index.",
- RunE: remove,
- Example: `podman manifest remove mylist:v1.11 sha256:15352d97781ffdf357bf3459c037be3efac4133dc9070c2dce7eca7c05c3e736`,
- Args: cobra.ExactArgs(2),
+ Use: "remove LIST IMAGE",
+ Short: "Remove an entry from a manifest list or image index",
+ Long: "Removes an image from a manifest list or image index.",
+ RunE: remove,
+ Example: `podman manifest remove mylist:v1.11 sha256:15352d97781ffdf357bf3459c037be3efac4133dc9070c2dce7eca7c05c3e736`,
+ Args: cobra.ExactArgs(2),
+ DisableFlagsInUseLine: true,
}
)
diff --git a/cmd/podman/networks/network.go b/cmd/podman/networks/network.go
index 7f38cd2cd..8f605f995 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 c26ca9853..909f225a8 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 b151e5f5d..bc2aa18be 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 34c07c11b..db2217aea 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/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/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 02089016e..d83e4d77e 100644
--- a/cmd/podman/pods/kill.go
+++ b/cmd/podman/pods/kill.go
@@ -4,9 +4,9 @@ import (
"context"
"fmt"
- "github.com/containers/libpod/cmd/podman/parse"
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/cmd/podman/utils"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/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 4ee182661..0ed3db936 100644
--- a/cmd/podman/pods/pause.go
+++ b/cmd/podman/pods/pause.go
@@ -4,9 +4,9 @@ import (
"context"
"fmt"
- "github.com/containers/libpod/cmd/podman/parse"
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/cmd/podman/utils"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/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 9dc538c71..ca0283b11 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 0171bb243..395acd78f 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 1f617a277..8bbbbb05d 100644
--- a/cmd/podman/pods/restart.go
+++ b/cmd/podman/pods/restart.go
@@ -4,9 +4,9 @@ import (
"context"
"fmt"
- "github.com/containers/libpod/cmd/podman/parse"
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/cmd/podman/utils"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/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 ec8dae1d1..5a5aa699b 100644
--- a/cmd/podman/pods/rm.go
+++ b/cmd/podman/pods/rm.go
@@ -5,9 +5,9 @@ import (
"fmt"
"github.com/containers/libpod/cmd/podman/common"
- "github.com/containers/libpod/cmd/podman/parse"
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/cmd/podman/utils"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/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 97020b360..7ca211baa 100644
--- a/cmd/podman/pods/start.go
+++ b/cmd/podman/pods/start.go
@@ -5,9 +5,9 @@ import (
"fmt"
"github.com/containers/libpod/cmd/podman/common"
- "github.com/containers/libpod/cmd/podman/parse"
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/cmd/podman/utils"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/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 d14632f01..619e49520 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/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/containers/libpod/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 628e8a536..cb052575a 100644
--- a/cmd/podman/pods/stop.go
+++ b/cmd/podman/pods/stop.go
@@ -5,9 +5,9 @@ import (
"fmt"
"github.com/containers/libpod/cmd/podman/common"
- "github.com/containers/libpod/cmd/podman/parse"
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/cmd/podman/utils"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/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 8df00f92a..d790869a4 100644
--- a/cmd/podman/pods/top.go
+++ b/cmd/podman/pods/top.go
@@ -8,6 +8,7 @@ import (
"text/tabwriter"
"github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/containers/libpod/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 b30bd930a..54553e4a8 100644
--- a/cmd/podman/pods/unpause.go
+++ b/cmd/podman/pods/unpause.go
@@ -4,9 +4,9 @@ import (
"context"
"fmt"
- "github.com/containers/libpod/cmd/podman/parse"
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/cmd/podman/utils"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/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 a67568d73..85a63402b 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/config_tunnel.go b/cmd/podman/registry/config_tunnel.go
index 4f9f51163..bb3da947e 100644
--- a/cmd/podman/registry/config_tunnel.go
+++ b/cmd/podman/registry/config_tunnel.go
@@ -2,13 +2,6 @@
package registry
-import (
- "os"
-)
-
func init() {
abiSupport = false
-
- // Enforce that podman-remote == podman --remote
- os.Args = append(os.Args, "--remote")
}
diff --git a/cmd/podman/registry/remote.go b/cmd/podman/registry/remote.go
index 95870750e..ed1a874d6 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/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 25e53cbee..45ca48c39 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 9f80a454b..8ee441446 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/renumber.go b/cmd/podman/system/renumber.go
index b90640de3..39cd15dd7 100644
--- a/cmd/podman/system/renumber.go
+++ b/cmd/podman/system/renumber.go
@@ -22,11 +22,12 @@ var (
`
renumberCommand = &cobra.Command{
- Use: "renumber",
- Args: validate.NoArgs,
- Short: "Migrate lock numbers",
- Long: renumberDescription,
- Run: renumber,
+ Use: "renumber",
+ Args: validate.NoArgs,
+ DisableFlagsInUseLine: true,
+ Short: "Migrate lock numbers",
+ Long: renumberDescription,
+ Run: renumber,
}
)
diff --git a/cmd/podman/system/system.go b/cmd/podman/system/system.go
index acf41a32d..7937e6df8 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/system/unshare.go b/cmd/podman/system/unshare.go
index e5d41e06d..109bab9ed 100644
--- a/cmd/podman/system/unshare.go
+++ b/cmd/podman/system/unshare.go
@@ -13,10 +13,11 @@ import (
var (
unshareDescription = "Runs a command in a modified user namespace."
unshareCommand = &cobra.Command{
- Use: "unshare [flags] [COMMAND [ARG ...]]",
- Short: "Run a command in a modified user namespace",
- Long: unshareDescription,
- RunE: unshare,
+ Use: "unshare [COMMAND [ARG ...]]",
+ DisableFlagsInUseLine: true,
+ Short: "Run a command in a modified user namespace",
+ Long: unshareDescription,
+ RunE: unshare,
Example: `podman unshare id
podman unshare cat /proc/self/uid_map,
podman unshare podman-script.sh`,
diff --git a/cmd/podman/validate/args.go b/cmd/podman/validate/args.go
index d170447ee..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"
@@ -28,8 +29,119 @@ func IDOrLatestArgs(cmd *cobra.Command, args []string) error {
if len(args) > 1 {
return fmt.Errorf("`%s` accepts at most one argument", cmd.CommandPath())
}
- if len(args) == 0 && !cmd.Flag("latest").Changed {
- return fmt.Errorf("`%s` requires a name, id, or the \"--latest\" flag", 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..6e2aa063b
--- /dev/null
+++ b/cmd/podman/validate/latest.go
@@ -0,0 +1,15 @@
+package validate
+
+import (
+ "github.com/containers/libpod/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 12947a6b1..93b15eb38 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/contrib/remote/containers.conf b/contrib/remote/containers.conf
new file mode 100644
index 000000000..45f58171a
--- /dev/null
+++ b/contrib/remote/containers.conf
@@ -0,0 +1,11 @@
+# The containers configuration file specifies all of the available configuration
+# command-line options/flags for container engine tools like Podman
+# but in a TOML format that can be easily modified and versioned.
+
+[engine]
+
+# Default Remote URI to access the Podman service.
+# Examples:
+# remote rootless ssh://engineering.lab.company.com/run/user/1000/podman/podman.sock
+# remote rootfull ssh://root@10.10.1.136:22/run/podman/podman.sock
+# remote_uri= ""
diff --git a/docs/source/markdown/podman-auto-update.1.md b/docs/source/markdown/podman-auto-update.1.md
index 90e581e42..f37280cda 100644
--- a/docs/source/markdown/podman-auto-update.1.md
+++ b/docs/source/markdown/podman-auto-update.1.md
@@ -4,7 +4,7 @@
podman-auto-update - Auto update containers according to their auto-update policy
## SYNOPSIS
-**podman auto-update**
+**podman auto-update** [*options*]
## DESCRIPTION
`podman auto-update` looks up containers with a specified "io.containers.autoupdate" label (i.e., the auto-update policy).
diff --git a/docs/source/markdown/podman-container-exists.1.md b/docs/source/markdown/podman-container-exists.1.md
index 3b4ca33e4..d24df2fc8 100644
--- a/docs/source/markdown/podman-container-exists.1.md
+++ b/docs/source/markdown/podman-container-exists.1.md
@@ -4,7 +4,7 @@
podman-container-exists - Check if a container exists in local storage
## SYNOPSIS
-**podman container exists** [*options*] *container*
+**podman container exists** *container*
## DESCRIPTION
**podman container exists** checks if a container exists in local storage. The **ID** or **Name**
diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md
index 3ec91a3ad..30ac54de2 100644
--- a/docs/source/markdown/podman-create.1.md
+++ b/docs/source/markdown/podman-create.1.md
@@ -78,9 +78,12 @@ If the host uses cgroups v1, the default is set to **host**. On cgroups v2 the
**--cgroups**=*mode*
Determines whether the container will create CGroups.
-Valid values are *enabled*, *disabled*, *no-conmon*, which the default being *enabled*.
+Valid values are *enabled*, *disabled*, *no-conmon*, *split*, which the default being *enabled*.
+
+The *enabled* option will create a new cgroup under the cgroup-parent.
The *disabled* option will force the container to not create CGroups, and thus conflicts with CGroup options (**--cgroupns** and **--cgroup-parent**).
The *no-conmon* option disables a new CGroup only for the conmon process.
+The *split* option splits the current cgroup in two sub-cgroups: one for conmon and one for the container payload. It is not possible to set *--cgroup-parent* with *split*.
**--cgroup-parent**=*path*
@@ -623,6 +626,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-healthcheck-run.1.md b/docs/source/markdown/podman-healthcheck-run.1.md
index 21f2d9b20..546d847eb 100644
--- a/docs/source/markdown/podman-healthcheck-run.1.md
+++ b/docs/source/markdown/podman-healthcheck-run.1.md
@@ -4,7 +4,7 @@
podman\-healthcheck\-run - Run a container healthcheck
## SYNOPSIS
-**podman healthcheck run** [*options*] *container*
+**podman healthcheck run** *container*
## DESCRIPTION
diff --git a/docs/source/markdown/podman-image-exists.1.md b/docs/source/markdown/podman-image-exists.1.md
index 3b7127b64..59f2145cc 100644
--- a/docs/source/markdown/podman-image-exists.1.md
+++ b/docs/source/markdown/podman-image-exists.1.md
@@ -4,7 +4,7 @@
podman-image-exists - Check if an image exists in local storage
## SYNOPSIS
-**podman image exists** [*options*] *image*
+**podman image exists** *image*
## DESCRIPTION
**podman image exists** checks if an image exists in local storage. The **ID** or **Name**
diff --git a/docs/source/markdown/podman-manifest-add.1.md b/docs/source/markdown/podman-manifest-add.1.md
index 82f2071b9..44815def5 100644
--- a/docs/source/markdown/podman-manifest-add.1.md
+++ b/docs/source/markdown/podman-manifest-add.1.md
@@ -4,7 +4,7 @@
podman\-manifest\-add - Add an image to a manifest list or image index
## SYNOPSIS
-**podman manifest add** *listnameorindexname* *imagename*
+**podman manifest add** [*options*] *listnameorindexname* *imagename*
## DESCRIPTION
diff --git a/docs/source/markdown/podman-manifest-annotate.1.md b/docs/source/markdown/podman-manifest-annotate.1.md
index 4450de7fd..25ad4642e 100644
--- a/docs/source/markdown/podman-manifest-annotate.1.md
+++ b/docs/source/markdown/podman-manifest-annotate.1.md
@@ -4,7 +4,7 @@
podman\-manifest\-annotate - Add or update information about an entry in a manifest list or image index
## SYNOPSIS
-**podman manifest annotate** [options...] *listnameorindexname* *imagemanifestdigest*
+**podman manifest annotate** [*options*] *listnameorindexname* *imagemanifestdigest*
## DESCRIPTION
diff --git a/docs/source/markdown/podman-manifest-push.1.md b/docs/source/markdown/podman-manifest-push.1.md
index ab3287a7c..33b2a24c5 100644
--- a/docs/source/markdown/podman-manifest-push.1.md
+++ b/docs/source/markdown/podman-manifest-push.1.md
@@ -4,7 +4,7 @@
podman\-manifest\-push - Push a manifest list or image index to a registry
## SYNOPSIS
-**podman manifest push** [options...] *listnameorindexname* *transport:details*
+**podman manifest push** [*options*] *listnameorindexname* *transport:details*
## DESCRIPTION
Pushes a manifest list or image index to a registry.
diff --git a/docs/source/markdown/podman-mount.1.md b/docs/source/markdown/podman-mount.1.md
index c7bfedb48..eaed1051e 100644
--- a/docs/source/markdown/podman-mount.1.md
+++ b/docs/source/markdown/podman-mount.1.md
@@ -4,9 +4,9 @@
podman\-mount - Mount a working container's root filesystem
## SYNOPSIS
-**podman mount** [*container* ...]
+**podman mount** [*options*] [*container* ...]
-**podman container mount** [*container* ...]
+**podman container mount** [*options*] [*container* ...]
## DESCRIPTION
Mounts the specified containers' root file system in a location which can be
diff --git a/docs/source/markdown/podman-network-inspect.1.md b/docs/source/markdown/podman-network-inspect.1.md
index 86fa2552e..c75c6788a 100644
--- a/docs/source/markdown/podman-network-inspect.1.md
+++ b/docs/source/markdown/podman-network-inspect.1.md
@@ -4,7 +4,7 @@
podman\-network\-inspect - Displays the raw CNI network configuration for one or more networks
## SYNOPSIS
-**podman network inspect** [*network* ...]
+**podman network inspect** [*options*] [*network* ...]
## DESCRIPTION
Display the raw (JSON format) network configuration. This command is not available for rootless users.
diff --git a/docs/source/markdown/podman-network-rm.1.md b/docs/source/markdown/podman-network-rm.1.md
index c71f0d8fd..9ce4d1cd8 100644
--- a/docs/source/markdown/podman-network-rm.1.md
+++ b/docs/source/markdown/podman-network-rm.1.md
@@ -4,7 +4,7 @@
podman\-network\-rm - Remove one or more CNI networks
## SYNOPSIS
-**podman network rm** [*network...*]
+**podman network rm** [*options*] [*network...*]
## DESCRIPTION
Delete one or more Podman networks.
diff --git a/docs/source/markdown/podman-pod-prune.1.md b/docs/source/markdown/podman-pod-prune.1.md
index 5b74adade..5b4c4661c 100644
--- a/docs/source/markdown/podman-pod-prune.1.md
+++ b/docs/source/markdown/podman-pod-prune.1.md
@@ -4,7 +4,7 @@
podman-pod-prune - Remove all stopped pods and their containers
## SYNOPSIS
-**podman pod prune**
+**podman pod prune** [*options*]
## DESCRIPTION
**podman pod prune** removes all stopped pods and their containers from local storage.
diff --git a/docs/source/markdown/podman-rmi.1.md b/docs/source/markdown/podman-rmi.1.md
index 2e093e9c8..58280e831 100644
--- a/docs/source/markdown/podman-rmi.1.md
+++ b/docs/source/markdown/podman-rmi.1.md
@@ -4,9 +4,9 @@
podman\-rmi - Removes one or more locally stored images
## SYNOPSIS
-**podman rmi** *image* [...]
+**podman rmi** [*options*] *image* [...]
-**podman image rm** *image* [...]
+**podman image rm** [*options*] *image* [...]
## DESCRIPTION
Removes one or more locally stored images.
diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md
index 88666d595..2e2adbc7e 100644
--- a/docs/source/markdown/podman-run.1.md
+++ b/docs/source/markdown/podman-run.1.md
@@ -89,14 +89,16 @@ Set the cgroup namespace mode for the container.
If the host uses cgroups v1, the default is set to **host**. On cgroups v2, the default is **private**.
-**--cgroups**=**enabled**|**disabled**|**no-conmon**
+**--cgroups**=**enabled**|**disabled**|**no-conmon**|**split**
Determines whether the container will create CGroups.
-Default is **enabled**. The **disabled** option will force the container
-to not create CGroups, and thus conflicts with CGroup options
-(**--cgroupns** and **--cgroup-parent**).
+Default is **enabled**.
+
+The **enabled** option will create a new cgroup under the cgroup-parent.
+The **disabled** option will force the container to not create CGroups, and thus conflicts with CGroup options (**--cgroupns** and **--cgroup-parent**).
The **no-conmon** option disables a new CGroup only for the **conmon** process.
+The **split** option splits the current cgroup in two sub-cgroups: one for conmon and one for the container payload. It is not possible to set **--cgroup-parent** with **split**.
**--cgroup-parent**=*path*
@@ -636,6 +638,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-migrate.1.md b/docs/source/markdown/podman-system-migrate.1.md
index 28db56dee..baabfd14b 100644
--- a/docs/source/markdown/podman-system-migrate.1.md
+++ b/docs/source/markdown/podman-system-migrate.1.md
@@ -4,7 +4,7 @@
podman\-system\-migrate - Migrate existing containers to a new podman version
## SYNOPSIS
-**podman system migrate**
+**podman system migrate** [*options*]
## DESCRIPTION
**podman system migrate** migrates containers to the latest podman version.
diff --git a/docs/source/markdown/podman-system-reset.1.md b/docs/source/markdown/podman-system-reset.1.md
index 432f275f4..f290e26d5 100644
--- a/docs/source/markdown/podman-system-reset.1.md
+++ b/docs/source/markdown/podman-system-reset.1.md
@@ -4,7 +4,7 @@
podman\-system\-reset - Reset storage back to initial state
## SYNOPSIS
-**podman system reset**
+**podman system reset** [*options*]
## DESCRIPTION
**podman system reset** removes all pods, containers, images and volumes.
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/docs/source/markdown/podman-umount.1.md b/docs/source/markdown/podman-umount.1.md
index 100c47b32..31a213f28 100644
--- a/docs/source/markdown/podman-umount.1.md
+++ b/docs/source/markdown/podman-umount.1.md
@@ -4,13 +4,13 @@
podman\-umount - Unmount a working container's root filesystem
## SYNOPSIS
-**podman umount** *container* [...]
+**podman umount** [*options*] *container* [...]
-**podman container umount** *container* [...]
+**podman container umount** [*options*] *container* [...]
-**podman container unmount** *container* [...]
+**podman container unmount** [*options*] *container* [...]
-**podman unmount** *container* [...]
+**podman unmount** [*options*] *container* [...]
## DESCRIPTION
Unmounts the specified containers' root file system, if no other processes
diff --git a/docs/source/markdown/podman-unshare.1.md b/docs/source/markdown/podman-unshare.1.md
index f2eb02814..239213981 100644
--- a/docs/source/markdown/podman-unshare.1.md
+++ b/docs/source/markdown/podman-unshare.1.md
@@ -4,7 +4,7 @@
podman\-unshare - Run a command inside of a modified user namespace
## SYNOPSIS
-**podman unshare** [*options*] [*--*] [*command*]
+**podman unshare** [*--*] [*command*]
## DESCRIPTION
Launches a process (by default, *$SHELL*) in a new user namespace. The user
diff --git a/docs/source/markdown/podman-untag.1.md b/docs/source/markdown/podman-untag.1.md
index c83a0544c..d6ed7f3ea 100644
--- a/docs/source/markdown/podman-untag.1.md
+++ b/docs/source/markdown/podman-untag.1.md
@@ -4,9 +4,9 @@
podman\-untag - Removes one or more names from a locally-stored image
## SYNOPSIS
-**podman untag** [*options*] *image* [*name*[:*tag*]...]
+**podman untag** *image* [*name*[:*tag*]...]
-**podman image untag** [*options*] *image* [*name*[:*tag*]...]
+**podman image untag** *image* [*name*[:*tag*]...]
## DESCRIPTION
Remove one or more names from an image in the local storage. The image can be referred to by ID or reference. If a no name is specified, all names are removed the image. If a specified name is a short name and does not include a registry `localhost/` will be prefixed (e.g., `fedora` -> `localhost/fedora`). If a specified name does not include a tag `:latest` will be appended (e.g., `localhost/fedora` -> `localhost/fedora:latest`).
diff --git a/go.mod b/go.mod
index d02dfa0b4..64981efc1 100644
--- a/go.mod
+++ b/go.mod
@@ -11,7 +11,7 @@ require (
github.com/containernetworking/cni v0.7.2-0.20200304161608-4fae32b84921
github.com/containernetworking/plugins v0.8.6
github.com/containers/buildah v1.15.0
- github.com/containers/common v0.14.0
+ github.com/containers/common v0.14.3
github.com/containers/conmon v2.0.18+incompatible
github.com/containers/image/v5 v5.5.1
github.com/containers/psgo v1.5.1
diff --git a/go.sum b/go.sum
index fdc506fac..e069825da 100644
--- a/go.sum
+++ b/go.sum
@@ -70,6 +70,8 @@ github.com/containers/buildah v1.15.0 h1:p9cYJwcQ5Fnv0iBeHAFwHR0K+kcv7LbyAjUtc+H
github.com/containers/buildah v1.15.0/go.mod h1:j0AY2kWpmaOPPV5GKDJY9dMtekk5WMmMhcB+z0OW+vc=
github.com/containers/common v0.14.0 h1:hiZFDPf6ajKiDmojN5f5X3gboKPO73NLrYb0RXfrQiA=
github.com/containers/common v0.14.0/go.mod h1:9olhlE+WhYof1npnMJdyRMX14/yIUint6zyHzcyRVAg=
+github.com/containers/common v0.14.3 h1:LNsRPkap5Q/EqPyhiLKRZg8u629U8CEeoB49ilG6ZR4=
+github.com/containers/common v0.14.3/go.mod h1:9olhlE+WhYof1npnMJdyRMX14/yIUint6zyHzcyRVAg=
github.com/containers/conmon v2.0.18+incompatible h1:rjwjNnE756NuXcdE/uUmj4kDbrykslPuBMHI31wh43E=
github.com/containers/conmon v2.0.18+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
github.com/containers/image/v5 v5.4.4/go.mod h1:g7cxNXitiLi6pEr9/L9n/0wfazRuhDKXU15kV86N8h8=
diff --git a/hack/man-page-checker b/hack/man-page-checker
index 17d85d65d..d2cc6c6e1 100755
--- a/hack/man-page-checker
+++ b/hack/man-page-checker
@@ -3,6 +3,14 @@
# man-page-checker - validate and cross-reference man page names
#
+verbose=
+for i; do
+ case "$i" in
+ -v|--verbose) verbose=verbose ;;
+ esac
+done
+
+
die() {
echo "$(basename $0): $*" >&2
exit 1
@@ -65,6 +73,61 @@ for md in $(ls -1 *-*.1.md | grep -v remote);do
fi
done
+# Helper function: compares man page synopsis vs --help usage message
+function compare_usage() {
+ local cmd="$1"
+ local from_man="$2"
+
+ # Sometimes in CI we run before podman gets built.
+ test -x ../../../bin/podman || return
+
+ # Run 'cmd --help', grab the line immediately after 'Usage:'
+ local help_output=$(../../../bin/$cmd --help)
+ local from_help=$(echo "$help_output" | grep -A1 '^Usage:' | tail -1)
+
+ # strip off command name from both
+ from_man=$(sed -e "s/\*\*$cmd\*\*[[:space:]]*//" <<<"$from_man")
+ from_help=$(sed -e "s/^[[:space:]]*$cmd[[:space:]]*//" <<<"$from_help")
+
+ # man page lists 'foo [*options*]', help msg shows 'foo [flags]'.
+ # Make sure if one has it, the other does too.
+ if expr "$from_man" : "\[\*options\*\]" >/dev/null; then
+ if expr "$from_help" : "\[flags\]" >/dev/null; then
+ :
+ else
+ echo "WARNING: $cmd: man page shows '[*options*]', help does not show [flags]"
+ rc=1
+ fi
+ elif expr "$from_help" : "\[flags\]" >/dev/null; then
+ echo "WARNING: $cmd: --help shows [flags], man page does not show [*options*]"
+ rc=1
+ fi
+
+ # Strip off options and flags; start comparing arguments
+ from_man=$(sed -e 's/^\[\*options\*\][[:space:]]*//' <<<"$from_man")
+ from_help=$(sed -e 's/^\[flags\][[:space:]]*//' <<<"$from_help")
+
+ # Args in man page are '*foo*', in --help are 'FOO'. Convert all to
+ # UPCASE simply because it stands out better to the eye.
+ from_man=$(sed -e 's/\*\([a-z-]\+\)\*/\U\1/g' <<<"$from_man")
+
+ # FIXME: one of the common patterns is for --help to show 'POD [POD...]'
+ # but man page show 'pod ...'. This conversion may help one day, but
+ # not yet: there are too many inconsistencies such as '[pod ...]'
+ # (brackets) and 'pod...' (no space between).
+# from_help=$(sed -e 's/\([A-Z]\+\)[[:space:]]\+\[\1[[:space:]]*\.\.\.\]/\1 .../' <<<"$from_help")
+
+ # Compare man-page and --help usage strings. For now, do so only
+ # when run with --verbose.
+ if [[ "$from_man" != "$from_help" ]]; then
+ if [ -n "$verbose" ]; then
+ printf "%-25s man='%s' help='%s'\n" "$cmd:" "$from_man" "$from_help"
+ # Yeah, we're not going to enable this as a blocker any time soon.
+ # rc=1
+ fi
+ fi
+}
+
# Pass 3: compare synopses.
#
# Make sure the SYNOPSIS line in podman-foo.1.md reads '**podman foo** ...'
@@ -87,9 +150,7 @@ for md in *.1.md;do
cmd=$(echo "$synopsis" | sed -e 's/\(.*\)\*\*.*/\1/' | tr -d \*)
md_nodash=$(basename "$md" .1.md | tr '-' ' ')
if [[ $md_nodash = 'podman auto update' ]]; then
- # podman-auto-update.1.md is special cased as it's structure differs
- # from that of other man pages where main and sub-commands split by
- # dashes.
+ # special case: the command is "auto-update", with a hyphen
md_nodash='podman auto-update'
fi
if [ "$cmd" != "$md_nodash" -a "$cmd" != "podman-remote" ]; then
@@ -111,8 +172,9 @@ for md in *.1.md;do
# (for debugging, and getting a sense of standard conventions)
#printf " %-32s ------ '%s'\n" $md "$synopsis"
- # FIXME: some day: run ./bin/podman "args", extract Usage,
- # strip off [flags] and [options], then compare arguments
+ # If bin/podman is available, run "cmd --help" and compare Usage
+ # messages. This is complicated, so do it in a helper function.
+ compare_usage "$md_nodash" "$synopsis"
done
diff --git a/libpod/container.go b/libpod/container.go
index c85249676..20688e3ee 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -17,6 +17,7 @@ import (
"github.com/containers/libpod/libpod/lock"
"github.com/containers/libpod/pkg/namespaces"
"github.com/containers/libpod/pkg/rootless"
+ "github.com/containers/libpod/utils"
"github.com/containers/storage"
"github.com/cri-o/ocicni/pkg/ocicni"
spec "github.com/opencontainers/runtime-spec/specs-go"
@@ -1089,10 +1090,25 @@ func (c *Container) NamespacePath(linuxNS LinuxNS) (string, error) { //nolint:in
// CGroupPath returns a cgroups "path" for a given container.
func (c *Container) CGroupPath() (string, error) {
- switch c.runtime.config.Engine.CgroupManager {
- case config.CgroupfsCgroupsManager:
+ switch {
+ case c.config.CgroupsMode == cgroupSplit:
+ if c.config.CgroupParent != "" {
+ return "", errors.Errorf("cannot specify cgroup-parent with cgroup-mode %q", cgroupSplit)
+ }
+ cg, err := utils.GetCgroupProcess(c.state.ConmonPID)
+ if err != nil {
+ return "", err
+ }
+ // Use the conmon cgroup for two reasons: we validate the container
+ // delegation was correct, and the conmon cgroup doesn't change at runtime
+ // while we are not sure about the container that can create sub cgroups.
+ if !strings.HasSuffix(cg, "supervisor") {
+ return "", errors.Errorf("invalid cgroup for conmon %q", cg)
+ }
+ return strings.TrimSuffix(cg, "/supervisor") + "/container", nil
+ case c.runtime.config.Engine.CgroupManager == config.CgroupfsCgroupsManager:
return filepath.Join(c.config.CgroupParent, fmt.Sprintf("libpod-%s", c.ID())), nil
- case config.SystemdCgroupsManager:
+ case c.runtime.config.Engine.CgroupManager == config.SystemdCgroupsManager:
if rootless.IsRootless() {
uid := rootless.GetRootlessUID()
parts := strings.SplitN(c.config.CgroupParent, "/", 2)
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 5ee6726e0..2c78f6bd2 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -31,6 +31,7 @@ import (
"github.com/containers/libpod/pkg/resolvconf"
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/pkg/util"
+ "github.com/containers/libpod/utils"
"github.com/containers/storage/pkg/archive"
securejoin "github.com/cyphar/filepath-securejoin"
"github.com/opencontainers/runc/libcontainer/user"
@@ -1505,8 +1506,17 @@ func (c *Container) getOCICgroupPath() (string, error) {
switch {
case (rootless.IsRootless() && !unified) || c.config.NoCgroups:
return "", nil
+ case c.config.CgroupsMode == cgroupSplit:
+ if c.config.CgroupParent != "" {
+ return c.config.CgroupParent, nil
+ }
+ selfCgroup, err := utils.GetOwnCgroup()
+ if err != nil {
+ return "", err
+ }
+ return filepath.Join(selfCgroup, "container"), nil
case c.runtime.config.Engine.CgroupManager == config.SystemdCgroupsManager:
- // When runc is set to use Systemd as a cgroup manager, it
+ // When the OCI runtime is set to use Systemd as a cgroup manager, it
// expects cgroups to be passed as follows:
// slice:prefix:name
systemdCgroups := fmt.Sprintf("%s:libpod:%s", path.Base(c.config.CgroupParent), c.ID())
diff --git a/libpod/container_validate.go b/libpod/container_validate.go
index b7f0aadff..a53a1839d 100644
--- a/libpod/container_validate.go
+++ b/libpod/container_validate.go
@@ -34,6 +34,10 @@ func (c *Container) validate() error {
return errors.Wrapf(define.ErrInvalidArg, "cannot both create a network namespace and join another container's network namespace")
}
+ if c.config.CgroupsMode == cgroupSplit && c.config.CgroupParent != "" {
+ return errors.Wrapf(define.ErrInvalidArg, "cannot specify --cgroup-mode=split with a cgroup-parent")
+ }
+
// Not creating cgroups has a number of requirements, mostly related to
// the PID namespace.
if c.config.NoCgroups || c.config.CgroupsMode == "disabled" {
diff --git a/libpod/oci_conmon.go b/libpod/oci_conmon.go
new file mode 100644
index 000000000..74060b357
--- /dev/null
+++ b/libpod/oci_conmon.go
@@ -0,0 +1,7 @@
+package libpod
+
+const (
+ // cgroupSplit is the cgroup mode for reusing the current cgroup both
+ // for conmon and for the container payload.
+ cgroupSplit = "split"
+)
diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go
index d8a89047e..26e5d70b0 100644
--- a/libpod/oci_conmon_linux.go
+++ b/libpod/oci_conmon_linux.go
@@ -881,6 +881,12 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co
return err
}
+ if ctr.config.CgroupsMode == cgroupSplit {
+ if err := utils.MoveUnderCgroupSubtree("supervisor"); err != nil {
+ return err
+ }
+ }
+
args := r.sharedConmonArgs(ctr, ctr.ID(), ctr.bundlePath(), filepath.Join(ctr.state.RunDir, "pidfile"), ctr.LogPath(), r.exitsDir, ociLog, ctr.LogDriver(), logTag)
if ctr.config.Spec.Process.Terminal {
@@ -1173,7 +1179,7 @@ func (r *ConmonOCIRuntime) sharedConmonArgs(ctr *Container, cuuid, bundlePath, p
"--socket-dir-path", r.socketsDir,
}
- if r.cgroupManager == config.SystemdCgroupsManager && !ctr.config.NoCgroups {
+ if r.cgroupManager == config.SystemdCgroupsManager && !ctr.config.NoCgroups && ctr.config.CgroupsMode != cgroupSplit {
args = append(args, "-s")
}
@@ -1275,7 +1281,7 @@ func (r *ConmonOCIRuntime) moveConmonToCgroupAndSignal(ctr *Container, cmd *exec
// If cgroup creation is disabled - just signal.
switch ctr.config.CgroupsMode {
- case "disabled", "no-conmon":
+ case "disabled", "no-conmon", cgroupSplit:
mustCreateCgroup = false
}
diff --git a/libpod/options.go b/libpod/options.go
index cfc0397e3..4041fb1cf 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -1049,7 +1049,7 @@ func WithCgroupsMode(mode string) CtrCreateOption {
case "disabled":
ctr.config.NoCgroups = true
ctr.config.CgroupsMode = mode
- case "enabled", "no-conmon":
+ case "enabled", "no-conmon", cgroupSplit:
ctr.config.CgroupsMode = mode
default:
return errors.Wrapf(define.ErrInvalidArg, "Invalid cgroup mode %q", mode)
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index 8bb6a4bcf..74647dab8 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -233,9 +233,9 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai
return nil, errors.Wrapf(err, "error retrieving pod %s cgroup", pod.ID())
}
ctr.config.CgroupParent = podCgroup
- case rootless.IsRootless():
+ case rootless.IsRootless() && ctr.config.CgroupsMode != cgroupSplit:
ctr.config.CgroupParent = SystemdDefaultRootlessCgroupParent
- default:
+ case ctr.config.CgroupsMode != cgroupSplit:
ctr.config.CgroupParent = SystemdDefaultCgroupParent
}
} else if len(ctr.config.CgroupParent) < 6 || !strings.HasSuffix(path.Base(ctr.config.CgroupParent), ".slice") {
diff --git a/libpod/volume.go b/libpod/volume.go
index ac5f61255..58d1f81a6 100644
--- a/libpod/volume.go
+++ b/libpod/volume.go
@@ -165,7 +165,7 @@ func (v *Volume) Config() (*VolumeConfig, error) {
// VolumeInUse goes through the container dependencies of a volume
// and checks if the volume is being used by any container.
-func (v *Volume) VolumesInUse() ([]string, error) {
+func (v *Volume) VolumeInUse() ([]string, error) {
v.lock.Lock()
defer v.lock.Unlock()
@@ -174,3 +174,13 @@ func (v *Volume) VolumesInUse() ([]string, error) {
}
return v.runtime.state.VolumeInUse(v)
}
+
+// IsDangling returns whether this volume is dangling (unused by any
+// containers).
+func (v *Volume) IsDangling() (bool, error) {
+ ctrs, err := v.VolumeInUse()
+ if err != nil {
+ return false, err
+ }
+ return len(ctrs) == 0, nil
+}
diff --git a/pkg/api/handlers/compat/networks.go b/pkg/api/handlers/compat/networks.go
index 0f1eca5e5..7209255d7 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/server/server.go b/pkg/api/server/server.go
index bd6a99b96..5b2f8bea2 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/filters/volumes.go b/pkg/domain/filters/volumes.go
index f97c3f570..b1b5e6319 100644
--- a/pkg/domain/filters/volumes.go
+++ b/pkg/domain/filters/volumes.go
@@ -61,6 +61,29 @@ func GenerateVolumeFilters(filters map[string][]string) ([]libpod.VolumeFilter,
}
return false
})
+ case "dangling":
+ danglingVal := val
+ invert := false
+ switch strings.ToLower(danglingVal) {
+ case "true", "1":
+ // Do nothing
+ case "false", "0":
+ // Dangling=false requires that we
+ // invert the result of IsDangling.
+ invert = true
+ default:
+ return nil, errors.Errorf("%q is not a valid value for the \"dangling\" filter - must be true or false", danglingVal)
+ }
+ vf = append(vf, func(v *libpod.Volume) bool {
+ dangling, err := v.IsDangling()
+ if err != nil {
+ return false
+ }
+ if invert {
+ return !dangling
+ }
+ return dangling
+ })
default:
return nil, errors.Errorf("%q is in an invalid volume filter", filter)
}
diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go
index 90002326e..0511289ab 100644
--- a/pkg/domain/infra/abi/system.go
+++ b/pkg/domain/infra/abi/system.go
@@ -330,7 +330,7 @@ func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.System
if err != nil {
return nil, err
}
- inUse, err := v.VolumesInUse()
+ inUse, err := v.VolumeInUse()
if err != nil {
return nil, err
}
diff --git a/pkg/ps/ps.go b/pkg/ps/ps.go
index b07eb7f9a..cbac2cb06 100644
--- a/pkg/ps/ps.go
+++ b/pkg/ps/ps.go
@@ -145,11 +145,15 @@ func ListContainerBatch(rt *libpod.Runtime, ctr *libpod.Container, opts entities
}
return nil
})
-
if batchErr != nil {
return entities.ListContainer{}, batchErr
}
+ portMappings, err := ctr.PortMappings()
+ if err != nil {
+ return entities.ListContainer{}, err
+ }
+
ps := entities.ListContainer{
Command: conConfig.Command,
Created: conConfig.CreatedTime.Unix(),
@@ -165,7 +169,7 @@ func ListContainerBatch(rt *libpod.Runtime, ctr *libpod.Container, opts entities
Names: []string{conConfig.Name},
Pid: pid,
Pod: conConfig.Pod,
- Ports: conConfig.PortMappings,
+ Ports: portMappings,
Size: size,
StartedAt: startedTime.Unix(),
State: conState.String(),
diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go
index e19c582b5..a04afa00f 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 1c34f622b..badb34999 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 91c8e68d1..5c06d3bc3 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 3d5bf03e5..361f09379 100644
--- a/pkg/specgen/specgen.go
+++ b/pkg/specgen/specgen.go
@@ -435,7 +435,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/systemd/generate/containers.go b/pkg/systemd/generate/containers.go
index bf6cb81b8..333f8ef88 100644
--- a/pkg/systemd/generate/containers.go
+++ b/pkg/systemd/generate/containers.go
@@ -69,8 +69,6 @@ type containerInfo struct {
const containerTemplate = headerTemplate + `
{{- if .BoundToServices}}
-RefuseManualStart=yes
-RefuseManualStop=yes
BindsTo={{- range $index, $value := .BoundToServices -}}{{if $index}} {{end}}{{ $value }}.service{{end}}
After={{- range $index, $value := .BoundToServices -}}{{if $index}} {{end}}{{ $value }}.service{{end}}
{{- end}}
diff --git a/pkg/systemd/generate/containers_test.go b/pkg/systemd/generate/containers_test.go
index 80f0996a1..e108251ea 100644
--- a/pkg/systemd/generate/containers_test.go
+++ b/pkg/systemd/generate/containers_test.go
@@ -88,8 +88,6 @@ Description=Podman container-foobar.service
Documentation=man:podman-generate-systemd(1)
Wants=network.target
After=network-online.target
-RefuseManualStart=yes
-RefuseManualStop=yes
BindsTo=a.service b.service c.service pod.service
After=a.service b.service c.service pod.service
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/test/e2e/inspect_test.go b/test/e2e/inspect_test.go
index 2fad38a36..ed7876d8a 100644
--- a/test/e2e/inspect_test.go
+++ b/test/e2e/inspect_test.go
@@ -7,6 +7,7 @@ import (
. "github.com/containers/libpod/test/utils"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
+ "github.com/opencontainers/selinux/go-selinux"
)
var _ = Describe("Podman inspect", func() {
@@ -263,4 +264,29 @@ var _ = Describe("Podman inspect", func() {
Expect(len(baseJSON)).To(Equal(1))
Expect(baseJSON[0].Name).To(Equal(ctrName))
})
+
+ It("podman inspect - HostConfig.SecurityOpt ", func() {
+ if !selinux.GetEnabled() {
+ Skip("SELinux not enabled")
+ }
+
+ ctrName := "hugo"
+ create := podmanTest.PodmanNoCache([]string{
+ "create", "--name", ctrName,
+ "--security-opt", "seccomp=unconfined",
+ "--security-opt", "label=type:spc_t",
+ "--security-opt", "label=level:s0",
+ ALPINE, "sh"})
+
+ create.WaitWithDefaultTimeout()
+ Expect(create.ExitCode()).To(Equal(0))
+
+ baseInspect := podmanTest.Podman([]string{"inspect", ctrName})
+ baseInspect.WaitWithDefaultTimeout()
+ Expect(baseInspect.ExitCode()).To(Equal(0))
+ baseJSON := baseInspect.InspectContainerToJSON()
+ Expect(len(baseJSON)).To(Equal(1))
+ Expect(baseJSON[0].HostConfig.SecurityOpt).To(Equal([]string{"label=type:spc_t,label=level:s0", "seccomp=unconfined"}))
+ })
+
})
diff --git a/test/e2e/ps_test.go b/test/e2e/ps_test.go
index 0dc8e01af..cfc0a415e 100644
--- a/test/e2e/ps_test.go
+++ b/test/e2e/ps_test.go
@@ -449,4 +449,21 @@ var _ = Describe("Podman ps", func() {
Expect(len(output)).To(Equal(1))
Expect(output[0]).To(Equal(ctrName))
})
+
+ It("podman ps test with port shared with pod", func() {
+ podName := "testPod"
+ pod := podmanTest.Podman([]string{"pod", "create", "-p", "8080:80", "--name", podName})
+ pod.WaitWithDefaultTimeout()
+ Expect(pod.ExitCode()).To(Equal(0))
+
+ ctrName := "testCtr"
+ session := podmanTest.Podman([]string{"run", "--name", ctrName, "-dt", "--pod", podName, ALPINE, "top"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ ps := podmanTest.Podman([]string{"ps", "--filter", fmt.Sprintf("name=%s", ctrName), "--format", "{{.Ports}}"})
+ ps.WaitWithDefaultTimeout()
+ Expect(ps.ExitCode()).To(Equal(0))
+ Expect(ps.OutputToString()).To(ContainSubstring("0.0.0.0:8080->80/tcp"))
+ })
})
diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go
index afba12ccd..cdfbd5530 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/volume_ls_test.go b/test/e2e/volume_ls_test.go
index 7664e64bb..d2d75af9e 100644
--- a/test/e2e/volume_ls_test.go
+++ b/test/e2e/volume_ls_test.go
@@ -1,6 +1,7 @@
package integration
import (
+ "fmt"
"os"
. "github.com/containers/libpod/test/utils"
@@ -82,4 +83,30 @@ var _ = Describe("Podman volume ls", func() {
Expect(len(session.OutputToStringArray())).To(Equal(2))
Expect(session.OutputToStringArray()[1]).To(ContainSubstring(volName))
})
+
+ It("podman volume ls with --filter dangling", func() {
+ volName1 := "volume1"
+ session := podmanTest.Podman([]string{"volume", "create", volName1})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ volName2 := "volume2"
+ session2 := podmanTest.Podman([]string{"volume", "create", volName2})
+ session2.WaitWithDefaultTimeout()
+ Expect(session2.ExitCode()).To(Equal(0))
+
+ ctr := podmanTest.Podman([]string{"create", "-v", fmt.Sprintf("%s:/test", volName2), ALPINE, "sh"})
+ ctr.WaitWithDefaultTimeout()
+ Expect(ctr.ExitCode()).To(Equal(0))
+
+ lsNoDangling := podmanTest.Podman([]string{"volume", "ls", "--filter", "dangling=false", "--quiet"})
+ lsNoDangling.WaitWithDefaultTimeout()
+ Expect(lsNoDangling.ExitCode()).To(Equal(0))
+ Expect(lsNoDangling.OutputToString()).To(ContainSubstring(volName2))
+
+ lsDangling := podmanTest.Podman([]string{"volume", "ls", "--filter", "dangling=true", "--quiet"})
+ lsDangling.WaitWithDefaultTimeout()
+ Expect(lsDangling.ExitCode()).To(Equal(0))
+ Expect(lsDangling.OutputToString()).To(ContainSubstring(volName1))
+ })
})
diff --git a/test/python/dockerpy/README.md b/test/python/dockerpy/README.md
new file mode 100644
index 000000000..22908afc6
--- /dev/null
+++ b/test/python/dockerpy/README.md
@@ -0,0 +1,40 @@
+# Dockerpy regression test
+
+Python test suite to validate Podman endpoints using dockerpy library
+
+## Running Tests
+
+To run the tests locally in your sandbox (Fedora 32):
+
+```shell script
+# dnf install python3-docker
+```
+
+### Run the entire test suite
+
+```shell
+# cd test/python/dockerpy
+# PYTHONPATH=/usr/bin/python python -m unittest discover .
+```
+
+Passing the -v option to your test script will instruct unittest.main() to enable a higher level of verbosity, and produce detailed output:
+
+```shell
+# cd test/python/dockerpy
+# PYTHONPATH=/usr/bin/python python -m unittest -v discover .
+```
+
+### Run a specific test class
+
+```shell
+# cd test/python/dockerpy
+# PYTHONPATH=/usr/bin/python python -m unittest -v tests.test_images
+```
+
+### Run a specific test within the test class
+
+```shell
+# cd test/python/dockerpy
+# PYTHONPATH=/usr/bin/python python -m unittest tests.test_images.TestImages.test_import_image
+
+```
diff --git a/test/test_dockerpy/__init__.py b/test/python/dockerpy/__init__.py
index e69de29bb..e69de29bb 100644
--- a/test/test_dockerpy/__init__.py
+++ b/test/python/dockerpy/__init__.py
diff --git a/test/python/dockerpy/tests/__init__.py b/test/python/dockerpy/tests/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/test/python/dockerpy/tests/__init__.py
diff --git a/test/python/dockerpy/tests/common.py b/test/python/dockerpy/tests/common.py
new file mode 100644
index 000000000..f83f4076f
--- /dev/null
+++ b/test/python/dockerpy/tests/common.py
@@ -0,0 +1,105 @@
+import os
+import pathlib
+import subprocess
+import sys
+import time
+
+from docker import APIClient
+
+from . import constant
+
+alpineDict = {
+ "name": "docker.io/library/alpine:latest",
+ "shortName": "alpine",
+ "tarballName": "alpine.tar"
+}
+
+
+def get_client():
+ client = APIClient(base_url="http://localhost:8080", timeout=15)
+ return client
+
+
+client = get_client()
+
+
+def podman():
+ binary = os.getenv("PODMAN_BINARY")
+ if binary is None:
+ binary = "../../../bin/podman"
+ return binary
+
+
+def restore_image_from_cache(TestClass):
+ alpineImage = os.path.join(constant.ImageCacheDir,
+ alpineDict["tarballName"])
+ if not os.path.exists(alpineImage):
+ os.makedirs(constant.ImageCacheDir, exist_ok=True)
+ client.pull(constant.ALPINE)
+ image = client.get_image(constant.ALPINE)
+ tarball = open(alpineImage, mode="wb")
+ for frame in image:
+ tarball.write(frame)
+ tarball.close()
+ else:
+ subprocess.run(
+ [podman(), "load", "-i", alpineImage],
+ shell=False,
+ stdin=subprocess.DEVNULL,
+ stdout=subprocess.DEVNULL,
+ stderr=subprocess.DEVNULL,
+ check=True,
+ )
+
+
+def flush_image_cache(TestCase):
+ for f in pathlib.Path(constant.ImageCacheDir).glob("*"):
+ f.unlink(f)
+
+
+def run_top_container():
+ c = client.create_container(image=constant.ALPINE,
+ command='/bin/sleep 5',
+ name=constant.TOP)
+ client.start(container=c.get("Id"))
+ return c.get("Id")
+
+
+def enable_sock(TestClass):
+ TestClass.podman = subprocess.Popen(
+ [
+ podman(), "system", "service", "tcp:localhost:8080",
+ "--log-level=debug", "--time=0"
+ ],
+ shell=False,
+ stdin=subprocess.DEVNULL,
+ stdout=subprocess.DEVNULL,
+ stderr=subprocess.DEVNULL,
+ )
+ time.sleep(2)
+
+
+def terminate_connection(TestClass):
+ TestClass.podman.terminate()
+ stdout, stderr = TestClass.podman.communicate(timeout=0.5)
+ if stdout:
+ print("\nService Stdout:\n" + stdout.decode('utf-8'))
+ if stderr:
+ print("\nService Stderr:\n" + stderr.decode('utf-8'))
+
+ if TestClass.podman.returncode > 0:
+ sys.stderr.write("podman exited with error code {}\n".format(
+ TestClass.podman.returncode))
+ sys.exit(2)
+
+
+def remove_all_containers():
+ containers = client.containers(quiet=True)
+ for c in containers:
+ client.remove_container(container=c.get("Id"), force=True)
+
+
+def remove_all_images():
+ allImages = client.images()
+ for image in allImages:
+ client.remove_image(image, force=True)
diff --git a/test/python/dockerpy/tests/constant.py b/test/python/dockerpy/tests/constant.py
new file mode 100644
index 000000000..b44442d02
--- /dev/null
+++ b/test/python/dockerpy/tests/constant.py
@@ -0,0 +1,13 @@
+BB = "docker.io/library/busybox:latest"
+NGINX = "docker.io/library/nginx:latest"
+ALPINE = "docker.io/library/alpine:latest"
+ALPINE_SHORTNAME = "alpine"
+ALPINELISTTAG = "docker.io/library/alpine:3.10.2"
+ALPINELISTDIGEST = "docker.io/library/alpine@sha256:72c42ed48c3a2db31b7dafe17d275b634664a708d901ec9fd57b1529280f01fb"
+ALPINEAMD64DIGEST = "docker.io/library/alpine@sha256:acd3ca9941a85e8ed16515bfc5328e4e2f8c128caa72959a58a127b7801ee01f"
+ALPINEAMD64ID = "961769676411f082461f9ef46626dd7a2d1e2b2a38e6a44364bcbecf51e66dd4"
+ALPINEARM64DIGEST = "docker.io/library/alpine@sha256:db7f3dcef3d586f7dd123f107c93d7911515a5991c4b9e51fa2a43e46335a43e"
+ALPINEARM64ID = "915beeae46751fc564998c79e73a1026542e945ca4f73dc841d09ccc6c2c0672"
+infra = "k8s.gcr.io/pause:3.2"
+TOP = "top"
+ImageCacheDir = "/tmp/podman/imagecachedir"
diff --git a/test/test_dockerpy/test_containers.py b/test/python/dockerpy/tests/test_containers.py
index 34fe82c18..6b89688d4 100644
--- a/test/test_dockerpy/test_containers.py
+++ b/test/python/dockerpy/tests/test_containers.py
@@ -1,18 +1,15 @@
-
-import unittest
-import docker
-import requests
import os
-from docker import Client
-from . import constant
-from . import common
import time
+import unittest
+
+import requests
+
+from . import common, constant
client = common.get_client()
-class TestContainers(unittest.TestCase):
- podman = None
+class TestContainers(unittest.TestCase):
topContainerId = ""
def setUp(self):
@@ -33,6 +30,7 @@ class TestContainers(unittest.TestCase):
@classmethod
def tearDownClass(cls):
common.terminate_connection(cls)
+ common.flush_image_cache(cls)
return super().tearDownClass()
def test_inspect_container(self):
@@ -42,16 +40,15 @@ class TestContainers(unittest.TestCase):
self.assertEqual(error.exception.response.status_code, 404)
# Inspect valid container by name
container = client.inspect_container(constant.TOP)
- self.assertIn(TestContainers.topContainerId , container["Id"])
+ self.assertIn(TestContainers.topContainerId, container["Id"])
# Inspect valid container by Id
container = client.inspect_container(TestContainers.topContainerId)
- self.assertIn(constant.TOP , container["Name"])
+ self.assertIn(constant.TOP, container["Name"])
def test_create_container(self):
# Run a container with detach mode
container = client.create_container(image="alpine", detach=True)
- self.assertEqual(len(container),2)
-
+ self.assertEqual(len(container), 2)
def test_start_container(self):
# Start bogus container
@@ -65,9 +62,9 @@ class TestContainers(unittest.TestCase):
# self.assertEqual(error.exception.response.status_code, 304)
# Create a new container and validate the count
- client.create_container(image=constant.ALPINE,name="container2")
- containers = client.containers(quiet=True,all=True)
- self.assertEqual(len(containers),2)
+ client.create_container(image=constant.ALPINE, name="container2")
+ containers = client.containers(quiet=True, all=True)
+ self.assertEqual(len(containers), 2)
def test_stop_container(self):
# Stop bogus container
@@ -82,7 +79,10 @@ class TestContainers(unittest.TestCase):
# Stop a running container and validate the state
client.stop(TestContainers.topContainerId)
container = client.inspect_container(constant.TOP)
- self.assertIn(container["State"]["Status"],"stopped exited",)
+ self.assertIn(
+ container["State"]["Status"],
+ "stopped exited",
+ )
def test_restart_container(self):
# Restart bogus container
@@ -109,12 +109,12 @@ class TestContainers(unittest.TestCase):
# Remove container by ID with force
client.remove_container(TestContainers.topContainerId, force=True)
containers = client.containers()
- self.assertEqual(len(containers),0)
+ self.assertEqual(len(containers), 0)
def test_remove_container_without_force(self):
# Validate current container count
containers = client.containers()
- self.assertTrue(len(containers),1)
+ self.assertTrue(len(containers), 1)
# Remove running container should throw error
with self.assertRaises(requests.HTTPError) as error:
@@ -125,7 +125,7 @@ class TestContainers(unittest.TestCase):
client.stop(TestContainers.topContainerId)
client.remove_container(TestContainers.topContainerId)
containers = client.containers()
- self.assertEqual(len(containers),0)
+ self.assertEqual(len(containers), 0)
def test_pause_container(self):
# Pause bogus container
@@ -151,7 +151,6 @@ class TestContainers(unittest.TestCase):
client.pause(TestContainers.topContainerId)
self.assertEqual(error.exception.response.status_code, 500)
-
def test_unpause_container(self):
# Unpause bogus container
with self.assertRaises(requests.HTTPError) as error:
@@ -173,7 +172,7 @@ class TestContainers(unittest.TestCase):
# Add container and validate the count
client.create_container(image="alpine", detach=True)
containers = client.containers(all=True)
- self.assertEqual(len(containers),2)
+ self.assertEqual(len(containers), 2)
# Not working for now......checking
# # List container with filter by id
diff --git a/test/test_dockerpy/test_images.py b/test/python/dockerpy/tests/test_images.py
index c88353b79..5eae61c2f 100644
--- a/test/test_dockerpy/test_images.py
+++ b/test/python/dockerpy/tests/test_images.py
@@ -1,17 +1,18 @@
-
+import os
+import stat
import unittest
+from os import remove
+from stat import ST_SIZE
+
import docker
import requests
-import os
-from docker import Client
-from . import constant
-from . import common
+
+from . import common, constant
client = common.get_client()
-class TestImages(unittest.TestCase):
- podman = None
+class TestImages(unittest.TestCase):
def setUp(self):
super().setUp()
common.restore_image_from_cache(self)
@@ -25,13 +26,12 @@ class TestImages(unittest.TestCase):
super().setUpClass()
common.enable_sock(cls)
-
@classmethod
def tearDownClass(cls):
common.terminate_connection(cls)
+ common.flush_image_cache(cls)
return super().tearDownClass()
-
# Inspect Image
def test_inspect_image(self):
@@ -43,46 +43,46 @@ class TestImages(unittest.TestCase):
# Tag Image
- # Validates if invalid image name is given a bad response is encountered.
+# Validates if invalid image name is given a bad response is encountered.
+
def test_tag_invalid_image(self):
with self.assertRaises(requests.HTTPError):
- client.tag("dummy","demo")
-
-
+ client.tag("dummy", "demo")
# Validates if the image is tagged successfully.
def test_tag_valid_image(self):
- client.tag(constant.ALPINE,"demo",constant.ALPINE_SHORTNAME)
+ client.tag(constant.ALPINE, "demo", constant.ALPINE_SHORTNAME)
alpine_image = client.inspect_image(constant.ALPINE)
for x in alpine_image["RepoTags"]:
- if("demo:alpine" in x):
+ if ("demo:alpine" in x):
self.assertTrue
self.assertFalse
# Validates if name updates when the image is retagged.
@unittest.skip("dosent work now")
def test_retag_valid_image(self):
- client.tag(constant.ALPINE_SHORTNAME, "demo","rename")
+ client.tag(constant.ALPINE_SHORTNAME, "demo", "rename")
alpine_image = client.inspect_image(constant.ALPINE)
self.assertNotIn("demo:test", alpine_image["RepoTags"])
# List Image
- # List All Images
+# List All Images
+
def test_list_images(self):
allImages = client.images()
self.assertEqual(len(allImages), 1)
# Add more images
client.pull(constant.BB)
allImages = client.images()
- self.assertEqual(len(allImages) , 2)
-
+ self.assertEqual(len(allImages), 2)
- # List images with filter
- filters = {'reference':'alpine'}
- allImages = client.images(filters = filters)
- self.assertEqual(len(allImages) , 1)
+ # List images with filter
+ filters = {'reference': 'alpine'}
+ allImages = client.images(filters=filters)
+ self.assertEqual(len(allImages), 1)
# Search Image
+
def test_search_image(self):
response = client.search("alpine")
for i in response:
@@ -94,22 +94,25 @@ class TestImages(unittest.TestCase):
# Image Exist (No docker-py support yet)
# Remove Image
+
def test_remove_image(self):
# Check for error with wrong image name
with self.assertRaises(requests.HTTPError):
client.remove_image("dummy")
allImages = client.images()
- self.assertEqual(len(allImages) , 1)
+ self.assertEqual(len(allImages), 1)
alpine_image = client.inspect_image(constant.ALPINE)
client.remove_image(alpine_image)
allImages = client.images()
- self.assertEqual(len(allImages) , 0)
+ self.assertEqual(len(allImages), 0)
# Image History
+
def test_image_history(self):
# Check for error with wrong image name
with self.assertRaises(requests.HTTPError):
- client.remove_image("dummy")
+ client.history("dummy")
+
imageHistory = client.history(constant.ALPINE)
alpine_image = client.inspect_image(constant.ALPINE)
for h in imageHistory:
@@ -119,28 +122,37 @@ class TestImages(unittest.TestCase):
# Prune Image (No docker-py support yet)
+ def test_get_image_dummy(self):
+ # FIXME: seems to be an error in the library
+ self.skipTest("Documentation and library do not match")
+ # Check for error with wrong image name
+ with self.assertRaises(docker.errors.ImageNotFound):
+ client.get_image("dummy")
+
# Export Image
def test_export_image(self):
client.pull(constant.BB)
- file = os.path.join(constant.ImageCacheDir , "busybox.tar")
if not os.path.exists(constant.ImageCacheDir):
os.makedirs(constant.ImageCacheDir)
- # Check for error with wrong image name
- with self.assertRaises(requests.HTTPError):
- client.get_image("dummy")
- response = client.get_image(constant.BB)
- image_tar = open(file,mode="wb")
- image_tar.write(response.data)
- image_tar.close()
- os.stat(file)
+
+ image = client.get_image(constant.BB)
+
+ file = os.path.join(constant.ImageCacheDir, "busybox.tar")
+ tarball = open(file, mode="wb")
+ for frame in image:
+ tarball.write(frame)
+ tarball.close()
+ sz = os.path.getsize(file)
+ self.assertGreater(sz, 0)
+
# Import|Load Image
def test_import_image(self):
allImages = client.images()
self.assertEqual(len(allImages), 1)
- file = os.path.join(constant.ImageCacheDir , "busybox.tar")
+ file = os.path.join(constant.ImageCacheDir, "alpine.tar")
client.import_image_from_file(filename=file)
allImages = client.images()
self.assertEqual(len(allImages), 2)
diff --git a/test/test_dockerpy/test_info_version.py b/test/python/dockerpy/tests/test_info_version.py
index be1a2aab9..e3ee18ec7 100644
--- a/test/test_dockerpy/test_info_version.py
+++ b/test/python/dockerpy/tests/test_info_version.py
@@ -1,11 +1,10 @@
import unittest
-import docker
-from docker import Client
-from . import constant
-from . import common
+
+from . import common, constant
client = common.get_client()
+
class TestInfo_Version(unittest.TestCase):
podman = None
@@ -31,16 +30,15 @@ class TestInfo_Version(unittest.TestCase):
common.terminate_connection(cls)
return super().tearDownClass()
-
def test_Info(self):
self.assertIsNotNone(client.info())
def test_info_container_details(self):
info = client.info()
- self.assertEqual(info["Containers"],1)
+ self.assertEqual(info["Containers"], 1)
client.create_container(image=constant.ALPINE)
info = client.info()
- self.assertEqual(info["Containers"],2)
+ self.assertEqual(info["Containers"], 2)
def test_version(self):
self.assertIsNotNone(client.version())
diff --git a/test/system/015-help.bats b/test/system/015-help.bats
index 14af8e1a4..3d05b44fe 100644
--- a/test/system/015-help.bats
+++ b/test/system/015-help.bats
@@ -34,13 +34,16 @@ function check_help() {
dprint "$command_string --help"
run_podman "$@" $cmd --help
+ local full_help="$output"
# The line immediately after 'Usage:' gives us a 1-line synopsis
- usage=$(echo "$output" | grep -A1 '^Usage:' | tail -1)
+ usage=$(echo "$full_help" | grep -A1 '^Usage:' | tail -1)
[ -n "$usage" ] || die "podman $cmd: no Usage message found"
# e.g. 'podman ps' should not show 'podman container ps' in usage
- is "$usage" " $command_string .*" "Usage string matches command"
+ # Trailing space in usage handles 'podman system renumber' which
+ # has no ' [flags]'
+ is "$usage " " $command_string .*" "Usage string matches command"
# If usage ends in '[command]', recurse into subcommands
if expr "$usage" : '.*\[command\]$' >/dev/null; then
@@ -59,6 +62,17 @@ function check_help() {
die "'flags' must precede arguments in usage: $usage"
fi
+ # Cross-check: if usage includes '[flags]', there must be a
+ # longer 'Flags:' section in the full --help output; vice-versa,
+ # if 'Flags:' is in full output, usage line must have '[flags]'.
+ if expr "$usage" : '.*\[flag' >/dev/null; then
+ if ! expr "$full_help" : ".*Flags:" >/dev/null; then
+ die "$command_string: Usage includes '[flags]' but has no 'Flags:' subsection"
+ fi
+ elif expr "$full_help" : ".*Flags:" >/dev/null; then
+ die "$command_string: --help has 'Flags:' section but no '[flags]' in synopsis"
+ fi
+
# If usage lists no arguments (strings in ALL CAPS), confirm
# by running with 'invalid-arg' and expecting failure.
if ! expr "$usage" : '.*[A-Z]' >/dev/null; then
diff --git a/test/system/030-run.bats b/test/system/030-run.bats
index eeecea2e5..bc6347012 100644
--- a/test/system/030-run.bats
+++ b/test/system/030-run.bats
@@ -201,4 +201,45 @@ echo $rand | 0 | $rand
"podman will not overwrite existing cidfile"
}
+@test "podman run docker-archive" {
+ # Create an image that, when run, outputs a random magic string
+ expect=$(random_string 20)
+ run_podman run --name myc --entrypoint="[\"/bin/echo\",\"$expect\"]" $IMAGE
+ is "$output" "$expect" "podman run --entrypoint echo-randomstring"
+
+ # Save it as a tar archive
+ run_podman commit myc myi
+ archive=$PODMAN_TMPDIR/archive.tar
+ run_podman save myi -o $archive
+ is "$output" "" "podman save"
+
+ # Clean up image and container from container storage...
+ run_podman rmi myi
+ run_podman rm myc
+
+ # ... then confirm we can run from archive. This re-imports the image
+ # and runs it, producing our random string as the last line.
+ run_podman run docker-archive:$archive
+ is "${lines[0]}" "Getting image source signatures" "podman run docker-archive, first line of output"
+ is "$output" ".*Copying blob" "podman run docker-archive"
+ is "$output" ".*Copying config" "podman run docker-archive"
+ is "$output" ".*Writing manifest" "podman run docker-archive"
+ is "${lines[-1]}" "$expect" "podman run docker-archive: expected random string output"
+
+ # Clean up container as well as re-imported image
+ run_podman rm -a
+ run_podman rmi myi
+
+ # Repeat the above, with podman-create and podman-start.
+ run_podman create docker-archive:$archive
+ cid=${lines[-1]}
+
+ run_podman start --attach $cid
+ is "$output" "$expect" "'podman run' of 'podman-create docker-archive'"
+
+ # Clean up.
+ run_podman rm $cid
+ run_podman rmi myi
+}
+
# vim: filetype=sh
diff --git a/test/system/200-pod.bats b/test/system/200-pod.bats
index 9a6b39057..0e9d9132e 100644
--- a/test/system/200-pod.bats
+++ b/test/system/200-pod.bats
@@ -150,6 +150,18 @@ function random_ip() {
pod_id_file=${PODMAN_TMPDIR}/pod-id-file
+ # Randomly-assigned ports in the 5xxx and 6xxx range
+ for port_in in $(shuf -i 5000-5999);do
+ if ! { exec 3<> /dev/tcp/127.0.0.1/$port_in; } &>/dev/null; then
+ break
+ fi
+ done
+ for port_out in $(shuf -i 6000-6999);do
+ if ! { exec 3<> /dev/tcp/127.0.0.1/$port_out; } &>/dev/null; then
+ break
+ fi
+ done
+
# Create a pod with all the desired options
# FIXME: --ip=$ip fails:
# Error adding network: failed to allocate all requested IPs
@@ -161,6 +173,7 @@ function random_ip() {
--dns "$dns_server" \
--dns-search "$dns_search" \
--dns-opt "$dns_opt" \
+ --publish "$port_out:$port_in" \
--label "${labelname}=${labelvalue}"
pod_id="$output"
@@ -199,6 +212,34 @@ function random_ip() {
run_podman pod ps --no-trunc --filter "label=${labelname}=${labelvalue}" --format '{{.ID}}'
is "$output" "$pod_id" "pod ps --filter label=..."
+ # Test local port forwarding, as well as 'ps' output showing ports
+ # Run 'nc' in a container, waiting for input on the published port.
+ c_name=$(random_string 15)
+ run_podman run -d --pod mypod --name $c_name $IMAGE nc -l -p $port_in
+ cid="$output"
+
+ # Try running another container also listening on the same port.
+ run_podman 1 run --pod mypod --name dsfsdfsdf $IMAGE nc -l -p $port_in
+ is "$output" "nc: bind: Address in use" \
+ "two containers cannot bind to same port"
+
+ # While the container is still running, run 'podman ps' (no --format)
+ # and confirm that the output includes the published port
+ run_podman ps --filter id=$cid
+ is "${lines[1]}" "${cid:0:12} $IMAGE nc -l -p $port_in .* 0.0.0.0:$port_out->$port_in/tcp $c_name" \
+ "output of 'podman ps'"
+
+ # send a random string to the container. This will cause the container
+ # to output the string to its logs, then exit.
+ teststring=$(random_string 30)
+ echo "$teststring" | nc 127.0.0.1 $port_out
+
+ # Confirm that the container log output is the string we sent it.
+ run_podman logs $cid
+ is "$output" "$teststring" "test string received on container"
+
+ # Clean up
+ run_podman rm $cid
run_podman pod rm -f mypod
}
diff --git a/test/system/250-systemd.bats b/test/system/250-systemd.bats
index 4bee13414..b7035cdda 100644
--- a/test/system/250-systemd.bats
+++ b/test/system/250-systemd.bats
@@ -41,7 +41,7 @@ function teardown() {
fi
cname=$(random_string)
- run_podman create --name $cname --detach $IMAGE top
+ run_podman create --name $cname --label "io.containers.autoupdate=image" --detach $IMAGE top
run_podman generate systemd --new $cname
echo "$output" > "$UNIT_FILE"
@@ -64,6 +64,12 @@ function teardown() {
run_podman logs $cname
is "$output" ".*Load average:.*" "running container 'top'-like output"
+ # Exercise `podman auto-update`.
+ # TODO: this will at least run auto-update code but won't perform an update
+ # since the image didn't change. We need to improve on that and run
+ # an image from a local registry instead.
+ run_podman auto-update
+
# All good. Stop service, clean up.
run $SYSTEMCTL stop "$SERVICE_NAME"
if [ $status -ne 0 ]; then
diff --git a/test/system/410-selinux.bats b/test/system/410-selinux.bats
index 8a0477eff..1769730f0 100644
--- a/test/system/410-selinux.bats
+++ b/test/system/410-selinux.bats
@@ -63,4 +63,23 @@ function check_label() {
check_label "--security-opt label=level:s0:c1,c2" "container_t" "s0:c1,c2"
}
+# pr #6752
+@test "podman selinux: inspect multiple labels" {
+ if [ ! -e /usr/sbin/selinuxenabled ] || ! /usr/sbin/selinuxenabled; then
+ skip "selinux disabled or not available"
+ fi
+
+ run_podman run -d --name myc \
+ --security-opt seccomp=unconfined \
+ --security-opt label=type:spc_t \
+ --security-opt label=level:s0 \
+ $IMAGE sh -c 'while test ! -e /stop; do sleep 0.1; done'
+ run_podman inspect --format='{{ .HostConfig.SecurityOpt }}' myc
+ is "$output" "\[label=type:spc_t,label=level:s0 seccomp=unconfined]" \
+ "'podman inspect' preserves all --security-opts"
+
+ run_podman exec myc touch /stop
+ run_podman rm -f myc
+}
+
# vim: filetype=sh
diff --git a/test/test_dockerpy/README.md b/test/test_dockerpy/README.md
deleted file mode 100644
index 32e426d58..000000000
--- a/test/test_dockerpy/README.md
+++ /dev/null
@@ -1,30 +0,0 @@
-# Dockerpy regression test
-
-Python test suite to validate Podman endpoints using dockerpy library
-
-Running tests
-=============
-To run the tests locally in your sandbox:
-
-#### Run the entire test
-
-```
-sudo PYTHONPATH=/usr/bin/python python -m dockerpy.images
-```
-
-Passing the -v option to your test script will instruct unittest.main() to enable a higher level of verbosity, and produce detailed output:
-
-```
-sudo PYTHONPATH=/usr/bin/python python -m unittest -v dockerpy.images
-```
-#### Run a specific test class
-
-```
-sudo PYTHONPATH=/usr/bin/python python -m unittest -v dockerpy.images.TestImages
-```
-
-#### Run a specific test within the test class
-
-```
-sudo PYTHONPATH=/usr/bin/python python -m unittest -v dockerpy.images.TestImages.test_list_images
-```
diff --git a/test/test_dockerpy/common.py b/test/test_dockerpy/common.py
deleted file mode 100644
index 975b13dc6..000000000
--- a/test/test_dockerpy/common.py
+++ /dev/null
@@ -1,85 +0,0 @@
-import docker
-import subprocess
-import os
-import sys
-import time
-from docker import Client
-from . import constant
-
-alpineDict = {
- "name": "docker.io/library/alpine:latest",
- "shortName": "alpine",
- "tarballName": "alpine.tar"}
-
-def get_client():
- client = docker.Client(base_url="http://localhost:8080",timeout=15)
- return client
-
-client = get_client()
-
-def podman():
- binary = os.getenv("PODMAN_BINARY")
- if binary is None:
- binary = "bin/podman"
- return binary
-
-def restore_image_from_cache(TestClass):
- alpineImage = os.path.join(constant.ImageCacheDir , alpineDict["tarballName"])
- if not os.path.exists(alpineImage):
- os.makedirs(constant.ImageCacheDir)
- client.pull(constant.ALPINE)
- response = client.get_image(constant.ALPINE)
- image_tar = open(alpineImage,mode="wb")
- image_tar.write(response.data)
- image_tar.close()
- else :
- TestClass.podman = subprocess.run(
- [
- podman(), "load", "-i", alpineImage
- ],
- shell=False,
- stdin=subprocess.DEVNULL,
- stdout=subprocess.DEVNULL,
- stderr=subprocess.DEVNULL,
- )
-
-def run_top_container():
- c = client.create_container(image=constant.ALPINE,command='/bin/sleep 5',name=constant.TOP)
- client.start(container=c.get("Id"))
- return c.get("Id")
-
-def enable_sock(TestClass):
- TestClass.podman = subprocess.Popen(
- [
- podman(), "system", "service", "tcp:localhost:8080",
- "--log-level=debug", "--time=0"
- ],
- shell=False,
- stdin=subprocess.DEVNULL,
- stdout=subprocess.DEVNULL,
- stderr=subprocess.DEVNULL,
- )
- time.sleep(2)
-
-def terminate_connection(TestClass):
- TestClass.podman.terminate()
- stdout, stderr = TestClass.podman.communicate(timeout=0.5)
- if stdout:
- print("\nService Stdout:\n" + stdout.decode('utf-8'))
- if stderr:
- print("\nService Stderr:\n" + stderr.decode('utf-8'))
-
- if TestClass.podman.returncode > 0:
- sys.stderr.write("podman exited with error code {}\n".format(
- TestClass.podman.returncode))
- sys.exit(2)
-
-def remove_all_containers():
- containers = client.containers(quiet=True)
- for c in containers:
- client.remove_container(container=c.get("Id"), force=True)
-
-def remove_all_images():
- allImages = client.images()
- for image in allImages:
- client.remove_image(image,force=True)
diff --git a/test/test_dockerpy/constant.py b/test/test_dockerpy/constant.py
deleted file mode 100644
index 8a3f1d984..000000000
--- a/test/test_dockerpy/constant.py
+++ /dev/null
@@ -1,13 +0,0 @@
-BB = "docker.io/library/busybox:latest"
-NGINX = "docker.io/library/nginx:latest"
-ALPINE = "docker.io/library/alpine:latest"
-ALPINE_SHORTNAME = "alpine"
-ALPINELISTTAG = "docker.io/library/alpine:3.10.2"
-ALPINELISTDIGEST = "docker.io/library/alpine@sha256:72c42ed48c3a2db31b7dafe17d275b634664a708d901ec9fd57b1529280f01fb"
-ALPINEAMD64DIGEST = "docker.io/library/alpine@sha256:acd3ca9941a85e8ed16515bfc5328e4e2f8c128caa72959a58a127b7801ee01f"
-ALPINEAMD64ID = "961769676411f082461f9ef46626dd7a2d1e2b2a38e6a44364bcbecf51e66dd4"
-ALPINEARM64DIGEST = "docker.io/library/alpine@sha256:db7f3dcef3d586f7dd123f107c93d7911515a5991c4b9e51fa2a43e46335a43e"
-ALPINEARM64ID = "915beeae46751fc564998c79e73a1026542e945ca4f73dc841d09ccc6c2c0672"
-infra = "k8s.gcr.io/pause:3.2"
-TOP = "top"
-ImageCacheDir = "/tmp/podman/imagecachedir"
diff --git a/utils/utils_supported.go b/utils/utils_supported.go
index ce9fd5604..201ddb57b 100644
--- a/utils/utils_supported.go
+++ b/utils/utils_supported.go
@@ -3,10 +3,20 @@
package utils
import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+
"github.com/containers/libpod/pkg/cgroups"
"github.com/containers/libpod/pkg/rootless"
systemdDbus "github.com/coreos/go-systemd/v22/dbus"
"github.com/godbus/dbus/v5"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
)
// RunUnderSystemdScope adds the specified pid to a systemd scope
@@ -43,6 +53,118 @@ func RunUnderSystemdScope(pid int, slice string, unitName string) error {
return nil
}
+func getCgroupProcess(procFile string) (string, error) {
+ f, err := os.Open(procFile)
+ if err != nil {
+ return "", errors.Wrapf(err, "open file %q", procFile)
+ }
+ defer f.Close()
+
+ scanner := bufio.NewScanner(f)
+ cgroup := "/"
+ for scanner.Scan() {
+ line := scanner.Text()
+ parts := strings.Split(line, ":")
+ if len(parts) != 3 {
+ return "", errors.Errorf("cannot parse cgroup line %q", line)
+ }
+ if strings.HasPrefix(line, "0::") {
+ cgroup = line[3:]
+ break
+ }
+ // root cgroup, skip it
+ if parts[2] == "/" {
+ continue
+ }
+ // The process must have the same cgroup path for all controllers
+ // The OCI runtime spec file allow us to specify only one path.
+ if cgroup != "/" && cgroup != parts[2] {
+ return "", errors.Errorf("cgroup configuration not supported, the process is in two different cgroups")
+ }
+ cgroup = parts[2]
+ }
+ if cgroup == "/" {
+ return "", errors.Errorf("could not find cgroup mount in %q", procFile)
+ }
+ return cgroup, nil
+}
+
+// GetOwnCgroup returns the cgroup for the current process.
+func GetOwnCgroup() (string, error) {
+ return getCgroupProcess("/proc/self/cgroup")
+}
+
+// GetCgroupProcess returns the cgroup for the specified process process.
+func GetCgroupProcess(pid int) (string, error) {
+ return getCgroupProcess(fmt.Sprintf("/proc/%d/cgroup", pid))
+}
+
+// MoveUnderCgroupSubtree moves the PID under a cgroup subtree.
+func MoveUnderCgroupSubtree(subtree string) error {
+ procFile := "/proc/self/cgroup"
+ f, err := os.Open(procFile)
+ if err != nil {
+ return errors.Wrapf(err, "open file %q", procFile)
+ }
+ defer f.Close()
+
+ unifiedMode, err := cgroups.IsCgroup2UnifiedMode()
+ if err != nil {
+ return err
+ }
+
+ scanner := bufio.NewScanner(f)
+ for scanner.Scan() {
+ line := scanner.Text()
+ parts := strings.Split(line, ":")
+ if len(parts) != 3 {
+ return errors.Errorf("cannot parse cgroup line %q", line)
+ }
+
+ // root cgroup, skip it
+ if parts[2] == "/" {
+ continue
+ }
+
+ cgroupRoot := "/sys/fs/cgroup"
+ // Special case the unified mount on hybrid cgroup and named hierarchies.
+ // This works on Fedora 31, but we should really parse the mounts to see
+ // where the cgroup hierarchy is mounted.
+ if parts[1] == "" && !unifiedMode {
+ // If it is not using unified mode, the cgroup v2 hierarchy is
+ // usually mounted under /sys/fs/cgroup/unified
+ cgroupRoot = filepath.Join(cgroupRoot, "unified")
+ } else if parts[1] != "" {
+ // Assume the controller is mounted at /sys/fs/cgroup/$CONTROLLER.
+ controller := strings.TrimPrefix(parts[1], "name=")
+ cgroupRoot = filepath.Join(cgroupRoot, controller)
+ }
+
+ processes, err := ioutil.ReadFile(filepath.Join(cgroupRoot, parts[2], "cgroup.procs"))
+ if err != nil {
+ return err
+ }
+
+ newCgroup := filepath.Join(cgroupRoot, parts[2], subtree)
+ if err := os.Mkdir(newCgroup, 0755); err != nil {
+ return err
+ }
+
+ f, err := os.OpenFile(filepath.Join(newCgroup, "cgroup.procs"), os.O_RDWR, 0755)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+
+ for _, pid := range bytes.Split(processes, []byte("\n")) {
+ if _, err := f.Write(pid); err != nil {
+ logrus.Warnf("Cannot move process %s to cgroup %q", pid, newCgroup)
+ }
+ }
+ }
+ return nil
+}
+
func newProp(name string, units interface{}) systemdDbus.Property {
return systemdDbus.Property{
Name: name,
diff --git a/utils/utils_windows.go b/utils/utils_windows.go
index db27877d9..1a2196029 100644
--- a/utils/utils_windows.go
+++ b/utils/utils_windows.go
@@ -7,3 +7,15 @@ import "github.com/pkg/errors"
func RunUnderSystemdScope(pid int, slice string, unitName string) error {
return errors.New("not implemented for windows")
}
+
+func MoveUnderCgroupSubtree(subtree string) error {
+ return errors.New("not implemented for windows")
+}
+
+func GetOwnCgroup() (string, error) {
+ return "", errors.New("not implemented for windows")
+}
+
+func GetCgroupProcess(pid int) (string, error) {
+ return "", errors.New("not implemented for windows")
+}
diff --git a/vendor/github.com/containers/common/pkg/apparmor/apparmor.go b/vendor/github.com/containers/common/pkg/apparmor/apparmor.go
index 8b4207efc..8046f45f5 100644
--- a/vendor/github.com/containers/common/pkg/apparmor/apparmor.go
+++ b/vendor/github.com/containers/common/pkg/apparmor/apparmor.go
@@ -2,14 +2,16 @@ package apparmor
import (
"errors"
+
+ "github.com/containers/common/version"
)
const (
// ProfilePrefix is used for version-independent presence checks.
- ProfilePrefix = "apparmor_profile"
+ ProfilePrefix = "containers-default-"
// Profile default name
- Profile = "container-default"
+ Profile = ProfilePrefix + version.Version
)
var (
diff --git a/vendor/github.com/containers/common/pkg/apparmor/apparmor_linux.go b/vendor/github.com/containers/common/pkg/apparmor/apparmor_linux.go
index f0fab4597..307249f3d 100644
--- a/vendor/github.com/containers/common/pkg/apparmor/apparmor_linux.go
+++ b/vendor/github.com/containers/common/pkg/apparmor/apparmor_linux.go
@@ -255,9 +255,11 @@ func CheckProfileAndLoadDefault(name string) (string, error) {
}
}
- // If the specified name is not empty or is not a default libpod one,
- // ignore it and return the name.
- if name != "" && !strings.HasPrefix(name, ProfilePrefix) {
+ if name == "" {
+ name = Profile
+ } else if !strings.HasPrefix(name, ProfilePrefix) {
+ // If the specified name is not a default one, ignore it and return the
+ // name.
isLoaded, err := IsLoaded(name)
if err != nil {
return "", err
@@ -268,7 +270,6 @@ func CheckProfileAndLoadDefault(name string) (string, error) {
return name, nil
}
- name = Profile
// To avoid expensive redundant loads on each invocation, check
// if it's loaded before installing it.
isLoaded, err := IsLoaded(name)
diff --git a/vendor/github.com/containers/common/pkg/config/config.go b/vendor/github.com/containers/common/pkg/config/config.go
index ce479088e..d60464739 100644
--- a/vendor/github.com/containers/common/pkg/config/config.go
+++ b/vendor/github.com/containers/common/pkg/config/config.go
@@ -822,6 +822,7 @@ func stringsEq(a, b []string) bool {
var (
configOnce sync.Once
+ configErr error
config *Config
)
@@ -837,11 +838,10 @@ var (
// The system defaults container config files can be overwritten using the
// CONTAINERS_CONF environment variable. This is usually done for testing.
func Default() (*Config, error) {
- var err error
configOnce.Do(func() {
- config, err = NewConfig("")
+ config, configErr = NewConfig("")
})
- return config, err
+ return config, configErr
}
func Path() string {
diff --git a/vendor/github.com/containers/common/version/version.go b/vendor/github.com/containers/common/version/version.go
new file mode 100644
index 000000000..38a45dfb2
--- /dev/null
+++ b/vendor/github.com/containers/common/version/version.go
@@ -0,0 +1,4 @@
+package version
+
+// Version is the version of the build.
+const Version = "0.14.3"
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 882ea5d25..497381b52 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -84,13 +84,14 @@ github.com/containers/buildah/pkg/secrets
github.com/containers/buildah/pkg/supplemented
github.com/containers/buildah/pkg/umask
github.com/containers/buildah/util
-# github.com/containers/common v0.14.0
+# github.com/containers/common v0.14.3
github.com/containers/common/pkg/apparmor
github.com/containers/common/pkg/auth
github.com/containers/common/pkg/capabilities
github.com/containers/common/pkg/cgroupv2
github.com/containers/common/pkg/config
github.com/containers/common/pkg/sysinfo
+github.com/containers/common/version
# github.com/containers/conmon v2.0.18+incompatible
github.com/containers/conmon/runner/config
# github.com/containers/image/v5 v5.5.1