summaryrefslogtreecommitdiff
path: root/cmd/podman
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/podman')
-rw-r--r--cmd/podman/containers/commit.go6
-rw-r--r--cmd/podman/containers/export.go2
-rw-r--r--cmd/podman/containers/inspect.go2
-rw-r--r--cmd/podman/containers/mount.go2
-rw-r--r--cmd/podman/containers/port.go3
-rw-r--r--cmd/podman/containers/ps.go7
-rw-r--r--cmd/podman/containers/top.go2
-rw-r--r--cmd/podman/generate/systemd.go2
-rw-r--r--cmd/podman/images/build.go1
-rw-r--r--cmd/podman/images/inspect.go2
-rw-r--r--cmd/podman/images/list.go2
-rw-r--r--cmd/podman/images/push.go19
-rw-r--r--cmd/podman/images/save.go4
-rw-r--r--cmd/podman/images/trust_show.go1
-rw-r--r--cmd/podman/inspect.go2
-rw-r--r--cmd/podman/main.go2
-rw-r--r--cmd/podman/manifest/create.go2
-rw-r--r--cmd/podman/networks/create.go12
-rw-r--r--cmd/podman/networks/inspect.go2
-rw-r--r--cmd/podman/pods/top.go2
-rw-r--r--cmd/podman/registry/config.go3
-rw-r--r--cmd/podman/registry/config_tunnel.go7
-rw-r--r--cmd/podman/root.go17
-rw-r--r--cmd/podman/system/connection.go209
-rw-r--r--cmd/podman/system/unshare.go2
-rw-r--r--cmd/podman/validate/args.go7
26 files changed, 271 insertions, 51 deletions
diff --git a/cmd/podman/containers/commit.go b/cmd/podman/containers/commit.go
index b3c3d7626..79e2a32a7 100644
--- a/cmd/podman/containers/commit.go
+++ b/cmd/podman/containers/commit.go
@@ -22,7 +22,7 @@ var (
Short: "Create new image based on the changed container",
Long: commitDescription,
RunE: commit,
- Args: cobra.MinimumNArgs(1),
+ Args: cobra.RangeArgs(1, 2),
Example: `podman commit -q --message "committing container to image" reverent_golick image-committed
podman commit -q --author "firstName lastName" reverent_golick image-committed
podman commit -q --pause=false containerID image-committed
@@ -30,7 +30,7 @@ var (
}
containerCommitCommand = &cobra.Command{
- Args: cobra.MinimumNArgs(1),
+ Args: commitCommand.Args,
Use: commitCommand.Use,
Short: commitCommand.Short,
Long: commitCommand.Long,
@@ -82,7 +82,7 @@ func init() {
func commit(cmd *cobra.Command, args []string) error {
container := args[0]
- if len(args) > 1 {
+ if len(args) == 2 {
commitOptions.ImageName = args[1]
}
if !commitOptions.Quiet {
diff --git a/cmd/podman/containers/export.go b/cmd/podman/containers/export.go
index bbb6a6bc9..66e768ccb 100644
--- a/cmd/podman/containers/export.go
+++ b/cmd/podman/containers/export.go
@@ -28,7 +28,7 @@ var (
}
containerExportCommand = &cobra.Command{
- Args: cobra.MinimumNArgs(1),
+ Args: cobra.ExactArgs(1),
Use: exportCommand.Use,
Short: exportCommand.Short,
Long: exportCommand.Long,
diff --git a/cmd/podman/containers/inspect.go b/cmd/podman/containers/inspect.go
index 8556ebe83..e49fcc2e0 100644
--- a/cmd/podman/containers/inspect.go
+++ b/cmd/podman/containers/inspect.go
@@ -10,7 +10,7 @@ import (
var (
// podman container _inspect_
inspectCmd = &cobra.Command{
- Use: "inspect [flags] CONTAINER",
+ Use: "inspect [flags] CONTAINER [CONTAINER...]",
Short: "Display the configuration of a container",
Long: `Displays the low-level information on a container identified by name or ID.`,
RunE: inspectExec,
diff --git a/cmd/podman/containers/mount.go b/cmd/podman/containers/mount.go
index 7f15616de..5c73cceaa 100644
--- a/cmd/podman/containers/mount.go
+++ b/cmd/podman/containers/mount.go
@@ -23,7 +23,7 @@ var (
`
mountCommand = &cobra.Command{
- Use: "mount [flags] [CONTAINER]",
+ Use: "mount [flags] [CONTAINER...]",
Short: "Mount a working container's root filesystem",
Long: mountDescription,
RunE: mount,
diff --git a/cmd/podman/containers/port.go b/cmd/podman/containers/port.go
index d058a6aaf..115adc2a7 100644
--- a/cmd/podman/containers/port.go
+++ b/cmd/podman/containers/port.go
@@ -89,6 +89,9 @@ func port(cmd *cobra.Command, args []string) error {
container = args[0]
}
port := ""
+ if len(args) > 2 {
+ return errors.Errorf("`port` accepts at most 2 arguments")
+ }
if len(args) > 1 && !portOpts.Latest {
port = args[1]
}
diff --git a/cmd/podman/containers/ps.go b/cmd/podman/containers/ps.go
index ffd2054a6..5d3c9263e 100644
--- a/cmd/podman/containers/ps.go
+++ b/cmd/podman/containers/ps.go
@@ -110,7 +110,12 @@ func checkFlags(c *cobra.Command) error {
}
func jsonOut(responses []entities.ListContainer) error {
- b, err := json.MarshalIndent(responses, "", " ")
+ r := make([]entities.ListContainer, 0)
+ for _, con := range responses {
+ con.CreatedAt = units.HumanDuration(time.Since(time.Unix(con.Created, 0))) + " ago"
+ r = append(r, con)
+ }
+ b, err := json.MarshalIndent(r, "", " ")
if err != nil {
return err
}
diff --git a/cmd/podman/containers/top.go b/cmd/podman/containers/top.go
index d2b11ec77..afab12a14 100644
--- a/cmd/podman/containers/top.go
+++ b/cmd/podman/containers/top.go
@@ -25,7 +25,7 @@ var (
topOptions = entities.TopOptions{}
topCommand = &cobra.Command{
- Use: "top [flags] CONTAINER [FORMAT-DESCRIPTORS|ARGS]",
+ Use: "top [flags] CONTAINER [FORMAT-DESCRIPTORS|ARGS...]",
Short: "Display the running processes of a container",
Long: topDescription,
RunE: top,
diff --git a/cmd/podman/generate/systemd.go b/cmd/podman/generate/systemd.go
index e4fdd8690..b4ab0f9df 100644
--- a/cmd/podman/generate/systemd.go
+++ b/cmd/podman/generate/systemd.go
@@ -20,7 +20,7 @@ var (
Short: "Generate systemd units.",
Long: systemdDescription,
RunE: systemd,
- Args: cobra.MinimumNArgs(1),
+ Args: cobra.ExactArgs(1),
Example: `podman generate systemd CTR
podman generate systemd --new --time 10 CTR
podman generate systemd --files --name POD`,
diff --git a/cmd/podman/images/build.go b/cmd/podman/images/build.go
index 23bfcab79..dfde896a1 100644
--- a/cmd/podman/images/build.go
+++ b/cmd/podman/images/build.go
@@ -45,6 +45,7 @@ var (
Long: buildDescription,
TraverseChildren: true,
RunE: build,
+ Args: cobra.MaximumNArgs(1),
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/inspect.go b/cmd/podman/images/inspect.go
index f6a10ba44..a1a9e91eb 100644
--- a/cmd/podman/images/inspect.go
+++ b/cmd/podman/images/inspect.go
@@ -10,7 +10,7 @@ import (
var (
// Command: podman image _inspect_
inspectCmd = &cobra.Command{
- Use: "inspect [flags] IMAGE",
+ Use: "inspect [flags] IMAGE [IMAGE...]",
Short: "Display the configuration of an image",
Long: `Displays the low-level information of an image identified by name or ID.`,
RunE: inspectExec,
diff --git a/cmd/podman/images/list.go b/cmd/podman/images/list.go
index b7a8b8911..de7cca40d 100644
--- a/cmd/podman/images/list.go
+++ b/cmd/podman/images/list.go
@@ -32,7 +32,7 @@ type listFlagType struct {
var (
// Command: podman image _list_
listCmd = &cobra.Command{
- Use: "list [FLAGS] [IMAGE]",
+ Use: "list [flags] [IMAGE]",
Aliases: []string{"ls"},
Args: cobra.MaximumNArgs(1),
Short: "List images in local storage",
diff --git a/cmd/podman/images/push.go b/cmd/podman/images/push.go
index a1614dc7a..7af2d9343 100644
--- a/cmd/podman/images/push.go
+++ b/cmd/podman/images/push.go
@@ -29,10 +29,11 @@ var (
// Command: podman push
pushCmd = &cobra.Command{
- Use: "push [flags] SOURCE DESTINATION",
+ Use: "push [flags] SOURCE [DESTINATION]",
Short: "Push an image to a specified destination",
Long: pushDescription,
RunE: imagePush,
+ Args: cobra.RangeArgs(1, 2),
Example: `podman push imageID docker://registry.example.com/repository:tag
podman push imageID oci-archive:/path/to/layout:image:tag`,
}
@@ -45,6 +46,7 @@ var (
Short: pushCmd.Short,
Long: pushCmd.Long,
RunE: pushCmd.RunE,
+ Args: pushCmd.Args,
Example: `podman image push imageID docker://registry.example.com/repository:tag
podman image push imageID oci-archive:/path/to/layout:image:tag`,
}
@@ -96,19 +98,8 @@ func pushFlags(flags *pflag.FlagSet) {
// imagePush is implement the command for pushing images.
func imagePush(cmd *cobra.Command, args []string) error {
- var source, destination string
- switch len(args) {
- case 1:
- source = args[0]
- destination = args[0]
- case 2:
- source = args[0]
- destination = args[1]
- case 0:
- fallthrough
- default:
- return errors.New("push requires at least one image name, or optionally a second to specify a different destination")
- }
+ source := args[0]
+ destination := args[len(args)-1]
// TLS verification in c/image is controlled via a `types.OptionalBool`
// which allows for distinguishing among set-true, set-false, unspecified
diff --git a/cmd/podman/images/save.go b/cmd/podman/images/save.go
index 56953e41c..9b03c1383 100644
--- a/cmd/podman/images/save.go
+++ b/cmd/podman/images/save.go
@@ -23,8 +23,8 @@ var (
saveDescription = `Save an image to docker-archive or oci-archive on the local machine. Default is docker-archive.`
saveCommand = &cobra.Command{
- Use: "save [flags] IMAGE",
- Short: "Save image to an archive",
+ Use: "save [flags] IMAGE [IMAGE...]",
+ Short: "Save image(s) to an archive",
Long: saveDescription,
RunE: save,
Args: func(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/images/trust_show.go b/cmd/podman/images/trust_show.go
index 23ee6c709..dbaa800a4 100644
--- a/cmd/podman/images/trust_show.go
+++ b/cmd/podman/images/trust_show.go
@@ -18,6 +18,7 @@ var (
Short: "Display trust policy for the system",
Long: showTrustDescription,
RunE: showTrust,
+ Args: cobra.MaximumNArgs(1),
Example: "",
}
)
diff --git a/cmd/podman/inspect.go b/cmd/podman/inspect.go
index a5fdaedc2..6c4607d88 100644
--- a/cmd/podman/inspect.go
+++ b/cmd/podman/inspect.go
@@ -10,7 +10,7 @@ import (
var (
// Command: podman _inspect_ Object_ID
inspectCmd = &cobra.Command{
- Use: "inspect [flags] {CONTAINER_ID | IMAGE_ID}",
+ 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,
diff --git a/cmd/podman/main.go b/cmd/podman/main.go
index 76ec7bc8e..f502e7a67 100644
--- a/cmd/podman/main.go
+++ b/cmd/podman/main.go
@@ -35,7 +35,7 @@ func main() {
_, found := c.Command.Annotations[registry.ParentNSRequired]
if rootless.IsRootless() && found {
c.Command.RunE = func(cmd *cobra.Command, args []string) error {
- return fmt.Errorf("cannot `%s` in rootless mode", cmd.CommandPath())
+ return fmt.Errorf("cannot run command %q in rootless mode", cmd.CommandPath())
}
}
diff --git a/cmd/podman/manifest/create.go b/cmd/podman/manifest/create.go
index 9c0097b90..2ab1fccea 100644
--- a/cmd/podman/manifest/create.go
+++ b/cmd/podman/manifest/create.go
@@ -20,7 +20,7 @@ var (
Example: `podman manifest create mylist:v1.11
podman manifest create mylist:v1.11 arch-specific-image-to-add
podman manifest create --all mylist:v1.11 transport:tagged-image-to-add`,
- Args: cobra.MinimumNArgs(1),
+ Args: cobra.RangeArgs(1, 2),
}
)
diff --git a/cmd/podman/networks/create.go b/cmd/podman/networks/create.go
index 5d28c7140..2d29beddd 100644
--- a/cmd/podman/networks/create.go
+++ b/cmd/podman/networks/create.go
@@ -8,7 +8,6 @@ import (
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/containers/libpod/pkg/network"
- "github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
@@ -20,6 +19,7 @@ var (
Short: "network create",
Long: networkCreateDescription,
RunE: networkCreate,
+ Args: cobra.MaximumNArgs(1),
Example: `podman network create podman1`,
Annotations: map[string]string{
registry.ParentNSRequired: "",
@@ -62,14 +62,10 @@ func networkCreate(cmd *cobra.Command, args []string) error {
if err := network.IsSupportedDriver(networkCreateOptions.Driver); err != nil {
return err
}
- if len(args) > 1 {
- return errors.Errorf("only one network can be created at a time")
- }
- if len(args) > 0 && !define.NameRegex.MatchString(args[0]) {
- return define.RegexError
- }
-
if len(args) > 0 {
+ if !define.NameRegex.MatchString(args[0]) {
+ return define.RegexError
+ }
name = args[0]
}
response, err := registry.ContainerEngine().NetworkCreate(registry.Context(), name, networkCreateOptions)
diff --git a/cmd/podman/networks/inspect.go b/cmd/podman/networks/inspect.go
index 1b2e89909..31269e836 100644
--- a/cmd/podman/networks/inspect.go
+++ b/cmd/podman/networks/inspect.go
@@ -16,7 +16,7 @@ import (
var (
networkinspectDescription = `Inspect network`
networkinspectCommand = &cobra.Command{
- Use: "inspect NETWORK [NETWORK...] [flags] ",
+ Use: "inspect [flags] NETWORK [NETWORK...]",
Short: "network inspect",
Long: networkinspectDescription,
RunE: networkInspect,
diff --git a/cmd/podman/pods/top.go b/cmd/podman/pods/top.go
index ba1efb638..8df00f92a 100644
--- a/cmd/podman/pods/top.go
+++ b/cmd/podman/pods/top.go
@@ -22,7 +22,7 @@ var (
topOptions = entities.PodTopOptions{}
topCommand = &cobra.Command{
- Use: "top [flags] POD [FORMAT-DESCRIPTORS|ARGS]",
+ Use: "top [flags] POD [FORMAT-DESCRIPTORS|ARGS...]",
Short: "Display the running processes of containers in a pod",
Long: topDescription,
RunE: top,
diff --git a/cmd/podman/registry/config.go b/cmd/podman/registry/config.go
index 49d5bca74..a67568d73 100644
--- a/cmd/podman/registry/config.go
+++ b/cmd/podman/registry/config.go
@@ -68,7 +68,6 @@ func newPodmanConfig() {
}
}
- // FIXME: for rootless, add flag to get the path to override configuration
cfg, err := config.NewConfig("")
if err != nil {
fmt.Fprint(os.Stderr, "Failed to obtain podman configuration: "+err.Error())
@@ -83,7 +82,7 @@ func newPodmanConfig() {
podmanOptions = entities.PodmanConfig{Config: cfg, EngineMode: mode}
}
-// SetXdgDirs ensures the XDG_RUNTIME_DIR env and XDG_CONFIG_HOME variables are set.
+// setXdgDirs ensures the XDG_RUNTIME_DIR env and XDG_CONFIG_HOME variables are set.
// containers/image uses XDG_RUNTIME_DIR to locate the auth file, XDG_CONFIG_HOME is
// use for the libpod.conf configuration file.
func setXdgDirs() error {
diff --git a/cmd/podman/registry/config_tunnel.go b/cmd/podman/registry/config_tunnel.go
index bb3da947e..4f9f51163 100644
--- a/cmd/podman/registry/config_tunnel.go
+++ b/cmd/podman/registry/config_tunnel.go
@@ -2,6 +2,13 @@
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/root.go b/cmd/podman/root.go
index 4f834e87d..25e53cbee 100644
--- a/cmd/podman/root.go
+++ b/cmd/podman/root.go
@@ -8,6 +8,7 @@ import (
"runtime/pprof"
"strings"
+ "github.com/containers/common/pkg/config"
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/pkg/domain/entities"
@@ -103,13 +104,13 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error {
// TODO: Remove trace statement in podman V2.1
logrus.Debugf("Called %s.PersistentPreRunE(%s)", cmd.Name(), strings.Join(os.Args, " "))
- cfg := registry.PodmanConfig()
-
// Help is a special case, no need for more setup
if cmd.Name() == "help" {
return nil
}
+ cfg := registry.PodmanConfig()
+
// Prep the engines
if _, err := registry.NewImageEngine(cmd, args); err != nil {
return err
@@ -211,10 +212,14 @@ 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)")
- // TODO Read uri from containers.config when available
- flags.StringVar(&opts.URI, "url", registry.DefaultAPIAddress(), "URL to access Podman service (CONTAINER_HOST)")
- flags.StringSliceVar(&opts.Identities, "identity", []string{}, "path to SSH identity file, (CONTAINER_SSHKEY)")
- flags.StringVar(&opts.PassPhrase, "passphrase", "", "passphrase for identity file (not secure, CONTAINER_PASSPHRASE), ssh-agent always supported")
+
+ 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\")")
diff --git a/cmd/podman/system/connection.go b/cmd/podman/system/connection.go
new file mode 100644
index 000000000..9f80a454b
--- /dev/null
+++ b/cmd/podman/system/connection.go
@@ -0,0 +1,209 @@
+package system
+
+import (
+ "bytes"
+ "fmt"
+ "net"
+ "net/url"
+ "os"
+ "os/user"
+ "regexp"
+
+ "github.com/containers/common/pkg/config"
+ "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/terminal"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+ "github.com/spf13/cobra"
+ "golang.org/x/crypto/ssh"
+ "golang.org/x/crypto/ssh/agent"
+)
+
+const schemaPattern = "^[A-Za-z][A-Za-z0-9+.-]*:"
+
+var (
+ // Skip creating engines since this command will obtain connection information to engine
+ noOp = func(cmd *cobra.Command, args []string) error {
+ return nil
+ }
+ connectionCmd = &cobra.Command{
+ Use: "connection [flags] DESTINATION",
+ Args: cobra.ExactArgs(1),
+ Long: `Store ssh destination information in podman configuration.
+ "destination" is of the form [user@]hostname or
+ an URI of the form ssh://[user@]hostname[:port]
+`,
+ Short: "Record remote ssh destination",
+ PersistentPreRunE: noOp,
+ PersistentPostRunE: noOp,
+ TraverseChildren: false,
+ RunE: connection,
+ Example: `podman system connection server.fubar.com
+ podman system connection --identity ~/.ssh/dev_rsa ssh://root@server.fubar.com:2222
+ podman system connection --identity ~/.ssh/dev_rsa --port 22 root@server.fubar.com`,
+ }
+
+ cOpts = struct {
+ Identity string
+ Port int
+ UDSPath string
+ }{}
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: connectionCmd,
+ Parent: systemCmd,
+ })
+
+ 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)")
+}
+
+func connection(cmd *cobra.Command, args []string) error {
+ // Default to ssh: schema if none given
+ dest := []byte(args[0])
+ if match, err := regexp.Match(schemaPattern, dest); err != nil {
+ return errors.Wrapf(err, "internal regex error %q", schemaPattern)
+ } else if !match {
+ dest = append([]byte("ssh://"), dest...)
+ }
+
+ uri, err := url.Parse(string(dest))
+ if err != nil {
+ return errors.Wrapf(err, "failed to parse %q", string(dest))
+ }
+
+ if uri.User.Username() == "" {
+ if uri.User, err = getUserInfo(uri); err != nil {
+ return err
+ }
+ }
+
+ if cmd.Flag("socket-path").Changed {
+ uri.Path = cmd.Flag("socket-path").Value.String()
+ }
+
+ if cmd.Flag("port").Changed {
+ uri.Host = net.JoinHostPort(uri.Hostname(), cmd.Flag("port").Value.String())
+ }
+
+ if uri.Port() == "" {
+ uri.Host = net.JoinHostPort(uri.Hostname(), cmd.Flag("port").DefValue)
+ }
+
+ if uri.Path == "" {
+ if uri.Path, err = getUDS(cmd, uri); err != nil {
+ return errors.Wrapf(err, "failed to connect to %q", uri.String())
+ }
+ }
+
+ custom, err := config.ReadCustomConfig()
+ if err != nil {
+ return err
+ }
+
+ if cmd.Flag("identity").Changed {
+ custom.Engine.RemoteIdentity = cOpts.Identity
+ }
+
+ custom.Engine.RemoteURI = uri.String()
+ return custom.Write()
+}
+
+func getUserInfo(uri *url.URL) (*url.Userinfo, error) {
+ var (
+ usr *user.User
+ err error
+ )
+ if u, found := os.LookupEnv("_CONTAINERS_ROOTLESS_UID"); found {
+ usr, err = user.LookupId(u)
+ if err != nil {
+ return nil, errors.Wrapf(err, "failed to find user %q", u)
+ }
+ } else {
+ usr, err = user.Current()
+ if err != nil {
+ return nil, errors.Wrapf(err, "failed to obtain current user")
+ }
+ }
+
+ pw, set := uri.User.Password()
+ if set {
+ return url.UserPassword(usr.Username, pw), nil
+ }
+ return url.User(usr.Username), nil
+}
+
+func getUDS(cmd *cobra.Command, uri *url.URL) (string, error) {
+ var authMethods []ssh.AuthMethod
+ passwd, set := uri.User.Password()
+ if set {
+ authMethods = append(authMethods, ssh.Password(passwd))
+ }
+
+ ident := cmd.Flag("identity")
+ if ident.Changed {
+ auth, err := terminal.PublicKey(ident.Value.String(), []byte(passwd))
+ if err != nil {
+ return "", errors.Wrapf(err, "Failed to read identity %q", ident.Value.String())
+ }
+ authMethods = append(authMethods, auth)
+ }
+
+ if sock, found := os.LookupEnv("SSH_AUTH_SOCK"); found {
+ logrus.Debugf("Found SSH_AUTH_SOCK %q, ssh-agent signer enabled", sock)
+
+ c, err := net.Dial("unix", sock)
+ if err != nil {
+ return "", err
+ }
+ a := agent.NewClient(c)
+ authMethods = append(authMethods, ssh.PublicKeysCallback(a.Signers))
+ }
+
+ config := &ssh.ClientConfig{
+ User: uri.User.Username(),
+ Auth: authMethods,
+ HostKeyCallback: ssh.InsecureIgnoreHostKey(),
+ }
+ dial, err := ssh.Dial("tcp", uri.Host, config)
+ if err != nil {
+ return "", errors.Wrapf(err, "failed to connect to %q", uri.Host)
+ }
+ defer dial.Close()
+
+ session, err := dial.NewSession()
+ if err != nil {
+ return "", errors.Wrapf(err, "failed to create new ssh session on %q", uri.Host)
+ }
+ defer session.Close()
+
+ // Override podman binary for testing etc
+ podman := "podman"
+ if v, found := os.LookupEnv("PODMAN_BINARY"); found {
+ podman = v
+ }
+ run := podman + " info --format=json"
+
+ var buffer bytes.Buffer
+ session.Stdout = &buffer
+ if err := session.Run(run); err != nil {
+ return "", errors.Wrapf(err, "failed to run %q", run)
+ }
+
+ var info define.Info
+ if err := json.Unmarshal(buffer.Bytes(), &info); err != nil {
+ return "", errors.Wrapf(err, "failed to parse 'podman info' results")
+ }
+
+ if info.Host.RemoteSocket == nil || len(info.Host.RemoteSocket.Path) == 0 {
+ return "", fmt.Errorf("remote podman %q failed to report its UDS socket", uri.Host)
+ }
+ return info.Host.RemoteSocket.Path, nil
+}
diff --git a/cmd/podman/system/unshare.go b/cmd/podman/system/unshare.go
index 7db5d36d2..e5d41e06d 100644
--- a/cmd/podman/system/unshare.go
+++ b/cmd/podman/system/unshare.go
@@ -13,7 +13,7 @@ import (
var (
unshareDescription = "Runs a command in a modified user namespace."
unshareCommand = &cobra.Command{
- Use: "unshare [flags] [COMMAND [ARG]]",
+ Use: "unshare [flags] [COMMAND [ARG ...]]",
Short: "Run a command in a modified user namespace",
Long: unshareDescription,
RunE: unshare,
diff --git a/cmd/podman/validate/args.go b/cmd/podman/validate/args.go
index 69240798f..d170447ee 100644
--- a/cmd/podman/validate/args.go
+++ b/cmd/podman/validate/args.go
@@ -25,8 +25,11 @@ func SubCommandExists(cmd *cobra.Command, args []string) error {
// IDOrLatestArgs used to validate a nameOrId was provided or the "--latest" flag
func IDOrLatestArgs(cmd *cobra.Command, args []string) error {
- if len(args) > 1 || (len(args) == 0 && !cmd.Flag("latest").Changed) {
- return fmt.Errorf("`%s` requires a name, id or the \"--latest\" flag", cmd.CommandPath())
+ if len(args) > 1 {
+ return fmt.Errorf("`%s` accepts at most one argument", cmd.CommandPath())
+ }
+ if len(args) == 0 && !cmd.Flag("latest").Changed {
+ return fmt.Errorf("`%s` requires a name, id, or the \"--latest\" flag", cmd.CommandPath())
}
return nil
}