summaryrefslogtreecommitdiff
path: root/cmd/podman
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/podman')
-rw-r--r--cmd/podman/attach.go2
-rw-r--r--cmd/podman/build.go2
-rw-r--r--cmd/podman/cliconfig/config.go3
-rw-r--r--cmd/podman/commands.go2
-rw-r--r--cmd/podman/common.go6
-rw-r--r--cmd/podman/container.go1
-rw-r--r--cmd/podman/exec.go2
-rw-r--r--cmd/podman/export.go7
-rw-r--r--cmd/podman/generate_kube.go4
-rw-r--r--cmd/podman/load.go70
-rw-r--r--cmd/podman/login.go2
-rw-r--r--cmd/podman/logs.go58
-rw-r--r--cmd/podman/main.go40
-rw-r--r--cmd/podman/mount.go2
-rw-r--r--cmd/podman/play_kube.go17
-rw-r--r--cmd/podman/pod_inspect.go9
-rw-r--r--cmd/podman/pod_kill.go2
-rw-r--r--cmd/podman/pod_restart.go14
-rw-r--r--cmd/podman/pod_stats.go2
-rw-r--r--cmd/podman/pod_top.go26
-rw-r--r--cmd/podman/ps.go4
-rw-r--r--cmd/podman/pull.go2
-rw-r--r--cmd/podman/push.go2
-rw-r--r--cmd/podman/restart.go83
-rw-r--r--cmd/podman/rm.go12
-rw-r--r--cmd/podman/run.go2
-rw-r--r--cmd/podman/runlabel.go30
-rw-r--r--cmd/podman/save.go8
-rw-r--r--cmd/podman/search.go21
-rw-r--r--cmd/podman/shared/container.go80
-rw-r--r--cmd/podman/shared/create.go2
-rw-r--r--cmd/podman/start.go10
-rw-r--r--cmd/podman/tree.go2
-rw-r--r--cmd/podman/umount.go2
-rw-r--r--cmd/podman/varlink/io.podman.varlink10
-rw-r--r--cmd/podman/version.go4
36 files changed, 344 insertions, 201 deletions
diff --git a/cmd/podman/attach.go b/cmd/podman/attach.go
index 08976cdaa..86e89cfd7 100644
--- a/cmd/podman/attach.go
+++ b/cmd/podman/attach.go
@@ -35,7 +35,7 @@ func init() {
flags := attachCommand.Flags()
flags.StringVar(&attachCommand.DetachKeys, "detach-keys", "", "Override the key sequence for detaching a container. Format is a single character [a-Z] or ctrl-<value> where <value> is one of: a-z, @, ^, [, , or _")
flags.BoolVar(&attachCommand.NoStdin, "no-stdin", false, "Do not attach STDIN. The default is false")
- flags.BoolVar(&attachCommand.SigProxy, "sig-proxy", true, "Proxy received signals to the process (default true)")
+ flags.BoolVar(&attachCommand.SigProxy, "sig-proxy", true, "Proxy received signals to the process")
flags.BoolVarP(&attachCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
markFlagHiddenForRemoteClient("latest", flags)
}
diff --git a/cmd/podman/build.go b/cmd/podman/build.go
index 72d78aff9..f0a67791a 100644
--- a/cmd/podman/build.go
+++ b/cmd/podman/build.go
@@ -52,7 +52,7 @@ func init() {
buildCommand.SetHelpTemplate(HelpTemplate())
buildCommand.SetUsageTemplate(UsageTemplate())
flags := buildCommand.Flags()
- flags.SetInterspersed(false)
+ flags.SetInterspersed(true)
budFlags := buildahcli.GetBudFlags(&budFlagsValues)
flag := budFlags.Lookup("pull")
diff --git a/cmd/podman/cliconfig/config.go b/cmd/podman/cliconfig/config.go
index cb9d9a338..1461c9f03 100644
--- a/cmd/podman/cliconfig/config.go
+++ b/cmd/podman/cliconfig/config.go
@@ -421,14 +421,15 @@ type RmiValues struct {
type RunlabelValues struct {
PodmanCommand
Authfile string
- Display bool
CertDir string
Creds string
+ Display bool
Name string
Opt1 string
Opt2 string
Opt3 string
Quiet bool
+ Replace bool
SignaturePolicy string
TlsVerify bool
}
diff --git a/cmd/podman/commands.go b/cmd/podman/commands.go
index d37af70c1..810c5a6f6 100644
--- a/cmd/podman/commands.go
+++ b/cmd/podman/commands.go
@@ -21,7 +21,6 @@ func getMainCommands() []*cobra.Command {
&_psCommand,
_loginCommand,
_logoutCommand,
- _logsCommand,
_mountCommand,
_pauseCommand,
_portCommand,
@@ -63,7 +62,6 @@ func getContainerSubCommands() []*cobra.Command {
_execCommand,
_exportCommand,
_killCommand,
- _logsCommand,
_mountCommand,
_pauseCommand,
_portCommand,
diff --git a/cmd/podman/common.go b/cmd/podman/common.go
index b76037297..8b42ed673 100644
--- a/cmd/podman/common.go
+++ b/cmd/podman/common.go
@@ -264,7 +264,7 @@ func getCreateFlags(c *cliconfig.PodmanCommand) {
"entrypoint", "",
"Overwrite the default ENTRYPOINT of the image",
)
- createFlags.StringSliceP(
+ createFlags.StringArrayP(
"env", "e", []string{},
"Set environment variables in container",
)
@@ -313,7 +313,7 @@ func getCreateFlags(c *cliconfig.PodmanCommand) {
)
createFlags.String(
"image-volume", "bind",
- "Tells podman how to handle the builtin image volumes. The options are: 'bind', 'tmpfs', or 'ignore' (default 'bind')",
+ "Tells podman how to handle the builtin image volumes. The options are: 'bind', 'tmpfs', or 'ignore'",
)
createFlags.Bool(
"init", false,
@@ -374,7 +374,7 @@ func getCreateFlags(c *cliconfig.PodmanCommand) {
)
createFlags.Int64(
"memory-swappiness", -1,
- "Tune container memory swappiness (0 to 100) (default -1)",
+ "Tune container memory swappiness (0 to 100, or -1 for system default)",
)
createFlags.String(
"name", "",
diff --git a/cmd/podman/container.go b/cmd/podman/container.go
index ce6ad8883..2e9cedbaa 100644
--- a/cmd/podman/container.go
+++ b/cmd/podman/container.go
@@ -53,6 +53,7 @@ var (
_containerExistsCommand,
_contInspectSubCommand,
_listSubCommand,
+ _logsCommand,
}
)
diff --git a/cmd/podman/exec.go b/cmd/podman/exec.go
index aa81edf56..a6afbf75a 100644
--- a/cmd/podman/exec.go
+++ b/cmd/podman/exec.go
@@ -41,7 +41,7 @@ func init() {
execCommand.SetUsageTemplate(UsageTemplate())
flags := execCommand.Flags()
flags.SetInterspersed(false)
- flags.StringSliceVarP(&execCommand.Env, "env", "e", []string{}, "Set environment variables")
+ flags.StringArrayVarP(&execCommand.Env, "env", "e", []string{}, "Set environment variables")
flags.BoolVarP(&execCommand.Interfactive, "interactive", "i", false, "Not supported. All exec commands are interactive by default")
flags.BoolVarP(&execCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
flags.BoolVar(&execCommand.Privileged, "privileged", false, "Give the process extended Linux capabilities inside the container. The default is false")
diff --git a/cmd/podman/export.go b/cmd/podman/export.go
index e5dc410a7..92633facd 100644
--- a/cmd/podman/export.go
+++ b/cmd/podman/export.go
@@ -36,7 +36,7 @@ func init() {
exportCommand.SetHelpTemplate(HelpTemplate())
exportCommand.SetUsageTemplate(UsageTemplate())
flags := exportCommand.Flags()
- flags.StringVarP(&exportCommand.Output, "output", "o", "/dev/stdout", "Write to a file, default is STDOUT")
+ flags.StringVarP(&exportCommand.Output, "output", "o", "", "Write to a specified file (default: stdout, which must be redirected)")
}
// exportCmd saves a container to a tarball on disk
@@ -60,15 +60,16 @@ func exportCmd(c *cliconfig.ExportValues) error {
}
output := c.Output
- if runtime.Remote && (output == "/dev/stdout" || len(output) == 0) {
+ if runtime.Remote && len(output) == 0 {
return errors.New("remote client usage must specify an output file (-o)")
}
- if output == "/dev/stdout" {
+ if len(output) == 0 {
file := os.Stdout
if logrus.IsTerminal(file) {
return errors.Errorf("refusing to export to terminal. Use -o flag or redirect")
}
+ output = "/dev/stdout"
}
if err := parse.ValidateFileName(output); err != nil {
diff --git a/cmd/podman/generate_kube.go b/cmd/podman/generate_kube.go
index e3db14af3..42cfba8d8 100644
--- a/cmd/podman/generate_kube.go
+++ b/cmd/podman/generate_kube.go
@@ -57,8 +57,8 @@ func generateKubeYAMLCmd(c *cliconfig.GenerateKubeValues) error {
return errors.Wrapf(libpod.ErrNotImplemented, "rootless users")
}
args := c.InputArgs
- if len(args) > 1 || (len(args) < 1 && !c.Bool("latest")) {
- return errors.Errorf("you must provide one container|pod ID or name or --latest")
+ if len(args) != 1 {
+ return errors.Errorf("you must provide exactly one container|pod ID or name")
}
runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
diff --git a/cmd/podman/load.go b/cmd/podman/load.go
index 303c23bc7..04ff9fcca 100644
--- a/cmd/podman/load.go
+++ b/cmd/podman/load.go
@@ -5,21 +5,24 @@ import (
"io"
"io/ioutil"
"os"
+ "strings"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/shared/parse"
"github.com/containers/libpod/pkg/adapter"
"github.com/pkg/errors"
"github.com/spf13/cobra"
+ "golang.org/x/crypto/ssh/terminal"
)
var (
loadCommand cliconfig.LoadValues
- loadDescription = "Loads the image from docker-archive stored on the local machine."
- _loadCommand = &cobra.Command{
- Use: "load [flags] [PATH]",
- Short: "Load an image from docker archive",
+ loadDescription = "Loads an image from a locally stored archive (tar file) into container storage."
+
+ _loadCommand = &cobra.Command{
+ Use: "load [flags] [NAME[:TAG]]",
+ Short: "Load an image from container archive",
Long: loadDescription,
RunE: func(cmd *cobra.Command, args []string) error {
loadCommand.InputArgs = args
@@ -34,7 +37,7 @@ func init() {
loadCommand.SetHelpTemplate(HelpTemplate())
loadCommand.SetUsageTemplate(UsageTemplate())
flags := loadCommand.Flags()
- flags.StringVarP(&loadCommand.Input, "input", "i", "/dev/stdin", "Read from archive file, default is STDIN")
+ flags.StringVarP(&loadCommand.Input, "input", "i", "", "Read from specified archive file (default: stdin)")
flags.BoolVarP(&loadCommand.Quiet, "quiet", "q", false, "Suppress the output")
flags.StringVar(&loadCommand.SignaturePolicy, "signature-policy", "", "Pathname of signature policy file (not usually used)")
@@ -60,46 +63,43 @@ func loadCmd(c *cliconfig.LoadValues) error {
}
defer runtime.Shutdown(false)
- input := c.Input
- if runtime.Remote && len(input) == 0 {
- return errors.New("the remote client requires you to load via -i and a tarball")
- }
- if input == "/dev/stdin" {
- fi, err := os.Stdin.Stat()
- if err != nil {
+ if len(c.Input) > 0 {
+ if err := parse.ValidateFileName(c.Input); err != nil {
return err
}
- // checking if loading from pipe
- if !fi.Mode().IsRegular() {
- outFile, err := ioutil.TempFile("/var/tmp", "podman")
- if err != nil {
- return errors.Errorf("error creating file %v", err)
- }
- defer os.Remove(outFile.Name())
- defer outFile.Close()
-
- inFile, err := os.OpenFile(input, 0, 0666)
- if err != nil {
- return errors.Errorf("error reading file %v", err)
- }
- defer inFile.Close()
-
- _, err = io.Copy(outFile, inFile)
- if err != nil {
- return errors.Errorf("error copying file %v", err)
- }
+ } else {
+ if terminal.IsTerminal(int(os.Stdin.Fd())) {
+ return errors.Errorf("cannot read from terminal. Use command-line redirection or the --input flag.")
+ }
+ outFile, err := ioutil.TempFile("/var/tmp", "podman")
+ if err != nil {
+ return errors.Errorf("error creating file %v", err)
+ }
+ defer os.Remove(outFile.Name())
+ defer outFile.Close()
- input = outFile.Name()
+ _, err = io.Copy(outFile, os.Stdin)
+ if err != nil {
+ return errors.Errorf("error copying file %v", err)
}
- }
- if err := parse.ValidateFileName(input); err != nil {
- return err
+
+ c.Input = outFile.Name()
}
names, err := runtime.LoadImage(getContext(), imageName, c)
if err != nil {
return err
}
+ if len(imageName) > 0 {
+ split := strings.Split(names, ",")
+ newImage, err := runtime.NewImageFromLocal(split[0])
+ if err != nil {
+ return err
+ }
+ if err := newImage.TagImage(imageName); err != nil {
+ return errors.Wrapf(err, "error adding '%s' to image %q", imageName, newImage.InputName)
+ }
+ }
fmt.Println("Loaded image(s): " + names)
return nil
}
diff --git a/cmd/podman/login.go b/cmd/podman/login.go
index 43a7d246e..4e96b43cb 100644
--- a/cmd/podman/login.go
+++ b/cmd/podman/login.go
@@ -45,7 +45,7 @@ func init() {
flags.StringVar(&loginCommand.CertDir, "cert-dir", "", "Pathname of a directory containing TLS certificates and keys used to connect to the registry")
flags.BoolVar(&loginCommand.GetLogin, "get-login", true, "Return the current login user for the registry")
flags.StringVarP(&loginCommand.Password, "password", "p", "", "Password for registry")
- flags.BoolVar(&loginCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries (default: true)")
+ flags.BoolVar(&loginCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries")
flags.StringVarP(&loginCommand.Username, "username", "u", "", "Username for registry")
flags.BoolVar(&loginCommand.StdinPassword, "password-stdin", false, "Take the password from stdin")
diff --git a/cmd/podman/logs.go b/cmd/podman/logs.go
index c3416fe57..a1b5fb4cc 100644
--- a/cmd/podman/logs.go
+++ b/cmd/podman/logs.go
@@ -1,27 +1,24 @@
package main
import (
- "os"
"time"
"github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/libpod"
- "github.com/containers/libpod/pkg/logs"
+ "github.com/containers/libpod/pkg/adapter"
"github.com/containers/libpod/pkg/util"
"github.com/pkg/errors"
- "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
var (
logsCommand cliconfig.LogsValues
- logsDescription = `Retrieves logs for a container.
+ logsDescription = `Retrieves logs for one or more containers.
This does not guarantee execution order when combined with podman run (i.e. your run may not have generated any logs at the time you execute podman logs.
`
_logsCommand = &cobra.Command{
- Use: "logs [flags] CONTAINER",
+ Use: "logs [flags] CONTAINER [CONTAINER...]",
Short: "Fetch the logs of a container",
Long: logsDescription,
RunE: func(cmd *cobra.Command, args []string) error {
@@ -29,9 +26,19 @@ var (
logsCommand.GlobalFlags = MainGlobalOpts
return logsCmd(&logsCommand)
},
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) > 0 && logsCommand.Latest {
+ return errors.New("no containers can be specified when using 'latest'")
+ }
+ if !logsCommand.Latest && len(args) < 1 {
+ return errors.New("specify at least one container name or ID to log")
+ }
+ return nil
+ },
Example: `podman logs ctrID
podman logs --tail 2 mywebserver
- podman logs --follow=true --since 10m ctrID`,
+ podman logs --follow=true --since 10m ctrID
+ podman logs mywebserver mydbserver`,
}
)
@@ -54,20 +61,14 @@ func init() {
}
func logsCmd(c *cliconfig.LogsValues) error {
- var ctr *libpod.Container
var err error
- runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
+ runtime, err := adapter.GetRuntime(&c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
defer runtime.Shutdown(false)
- args := c.InputArgs
- if len(args) != 1 && !c.Latest {
- return errors.Errorf("'podman logs' requires exactly one container name/ID")
- }
-
sinceTime := time.Time{}
if c.Flag("since").Changed {
// parse time, error out if something is wrong
@@ -78,7 +79,7 @@ func logsCmd(c *cliconfig.LogsValues) error {
sinceTime = since
}
- opts := &logs.LogOptions{
+ opts := &libpod.LogOptions{
Details: c.Details,
Follow: c.Follow,
Since: sinceTime,
@@ -86,30 +87,5 @@ func logsCmd(c *cliconfig.LogsValues) error {
Timestamps: c.Timestamps,
}
- if c.Latest {
- ctr, err = runtime.GetLatestContainer()
- } else {
- ctr, err = runtime.LookupContainer(args[0])
- }
- if err != nil {
- return err
- }
-
- logPath := ctr.LogPath()
-
- state, err := ctr.State()
- if err != nil {
- return err
- }
-
- // If the log file does not exist yet and the container is in the
- // Configured state, it has never been started before and no logs exist
- // Exit cleanly in this case
- if _, err := os.Stat(logPath); err != nil {
- if state == libpod.ContainerStateConfigured {
- logrus.Debugf("Container has not been started, no logs exist yet")
- return nil
- }
- }
- return logs.ReadLogs(logPath, ctr, opts)
+ return runtime.Log(c, opts)
}
diff --git a/cmd/podman/main.go b/cmd/podman/main.go
index af6731d96..dd8b61408 100644
--- a/cmd/podman/main.go
+++ b/cmd/podman/main.go
@@ -45,6 +45,7 @@ var mainCommands = []*cobra.Command{
&_inspectCommand,
_killCommand,
_loadCommand,
+ _logsCommand,
podCommand.Command,
_pullCommand,
_pushCommand,
@@ -66,23 +67,26 @@ var cmdsNotRequiringRootless = map[*cobra.Command]bool{
_exportCommand: true,
//// `info` must be executed in an user namespace.
//// If this change, please also update libpod.refreshRootless()
- _loginCommand: true,
- _logoutCommand: true,
- _mountCommand: true,
- _killCommand: true,
- _pauseCommand: true,
- _podRmCommand: true,
- _podKillCommand: true,
- _podStatsCommand: true,
- _podStopCommand: true,
- _restartCommand: true,
- _rmCommand: true,
- _runCommand: true,
- _unpauseCommand: true,
- _searchCommand: true,
- _statsCommand: true,
- _stopCommand: true,
- _topCommand: true,
+ _loginCommand: true,
+ _logoutCommand: true,
+ _mountCommand: true,
+ _killCommand: true,
+ _pauseCommand: true,
+ _podRmCommand: true,
+ _podKillCommand: true,
+ _podRestartCommand: true,
+ _podStatsCommand: true,
+ _podStopCommand: true,
+ _podTopCommand: true,
+ _restartCommand: true,
+ &_psCommand: true,
+ _rmCommand: true,
+ _runCommand: true,
+ _unpauseCommand: true,
+ _searchCommand: true,
+ _statsCommand: true,
+ _stopCommand: true,
+ _topCommand: true,
}
var rootCmd = &cobra.Command{
@@ -115,7 +119,7 @@ func init() {
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.DefaultMountsFile, "default-mounts-file", "", "Path to default mounts file")
rootCmd.PersistentFlags().MarkHidden("defaults-mount-file")
rootCmd.PersistentFlags().StringSliceVar(&MainGlobalOpts.HooksDir, "hooks-dir", []string{}, "Set the OCI hooks directory path (may be set multiple times)")
- rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.LogLevel, "log-level", "error", "Log messages above specified level: debug, info, warn, error (default), fatal or panic")
+ rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.LogLevel, "log-level", "error", "Log messages above specified level: debug, info, warn, error, fatal or panic")
rootCmd.PersistentFlags().IntVar(&MainGlobalOpts.MaxWorks, "max-workers", 0, "The maximum number of workers for parallel operations")
rootCmd.PersistentFlags().MarkHidden("max-workers")
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.Namespace, "namespace", "", "Set the libpod namespace, used to create separate views of the containers and pods on the system")
diff --git a/cmd/podman/mount.go b/cmd/podman/mount.go
index 4381074ab..d074551ce 100644
--- a/cmd/podman/mount.go
+++ b/cmd/podman/mount.go
@@ -25,7 +25,7 @@ var (
`
_mountCommand = &cobra.Command{
- Use: "mount [flags] CONTAINER",
+ Use: "mount [flags] [CONTAINER]",
Short: "Mount a working container's root filesystem",
Long: mountDescription,
RunE: func(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/play_kube.go b/cmd/podman/play_kube.go
index 44aa4776b..10221a339 100644
--- a/cmd/podman/play_kube.go
+++ b/cmd/podman/play_kube.go
@@ -1,6 +1,7 @@
package main
import (
+ "context"
"fmt"
"io"
"io/ioutil"
@@ -59,7 +60,7 @@ func init() {
flags.StringVar(&playKubeCommand.Creds, "creds", "", "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry")
flags.BoolVarP(&playKubeCommand.Quiet, "quiet", "q", false, "Suppress output information when pulling images")
flags.StringVar(&playKubeCommand.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)")
- flags.BoolVar(&playKubeCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries (default: true)")
+ flags.BoolVar(&playKubeCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries")
}
func playKubeYAMLCmd(c *cliconfig.KubePlayValues) error {
@@ -186,7 +187,7 @@ func playKubeYAMLCmd(c *cliconfig.KubePlayValues) error {
if err != nil {
return err
}
- createConfig, err := kubeContainerToCreateConfig(container, runtime, newImage, namespaces, volumes)
+ createConfig, err := kubeContainerToCreateConfig(ctx, container, runtime, newImage, namespaces, volumes)
if err != nil {
return err
}
@@ -231,7 +232,7 @@ func getPodPorts(containers []v1.Container) []ocicni.PortMapping {
}
// kubeContainerToCreateConfig takes a v1.Container and returns a createconfig describing a container
-func kubeContainerToCreateConfig(containerYAML v1.Container, runtime *libpod.Runtime, newImage *image2.Image, namespaces map[string]string, volumes map[string]string) (*createconfig.CreateConfig, error) {
+func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container, runtime *libpod.Runtime, newImage *image2.Image, namespaces map[string]string, volumes map[string]string) (*createconfig.CreateConfig, error) {
var (
containerConfig createconfig.CreateConfig
envs map[string]string
@@ -243,6 +244,14 @@ func kubeContainerToCreateConfig(containerYAML v1.Container, runtime *libpod.Run
containerConfig.Name = containerYAML.Name
containerConfig.Tty = containerYAML.TTY
containerConfig.WorkDir = containerYAML.WorkingDir
+
+ imageData, _ := newImage.Inspect(ctx)
+
+ containerConfig.User = "0"
+ if imageData != nil {
+ containerConfig.User = imageData.Config.User
+ }
+
if containerConfig.SecurityOpts != nil {
if containerYAML.SecurityContext.ReadOnlyRootFilesystem != nil {
containerConfig.ReadOnlyRootfs = *containerYAML.SecurityContext.ReadOnlyRootFilesystem
@@ -280,6 +289,7 @@ func kubeContainerToCreateConfig(containerYAML v1.Container, runtime *libpod.Run
for _, e := range containerYAML.Env {
envs[e.Name] = e.Value
}
+ containerConfig.Env = envs
for _, volume := range containerYAML.VolumeMounts {
host_path, exists := volumes[volume.Name]
@@ -291,6 +301,5 @@ func kubeContainerToCreateConfig(containerYAML v1.Container, runtime *libpod.Run
}
containerConfig.Volumes = append(containerConfig.Volumes, fmt.Sprintf("%s:%s", host_path, volume.MountPath))
}
- containerConfig.Env = envs
return &containerConfig, nil
}
diff --git a/cmd/podman/pod_inspect.go b/cmd/podman/pod_inspect.go
index 79ffe2e6f..851f39aa0 100644
--- a/cmd/podman/pod_inspect.go
+++ b/cmd/podman/pod_inspect.go
@@ -14,7 +14,7 @@ var (
podInspectCommand cliconfig.PodInspectValues
podInspectDescription = `Display the configuration for a pod by name or id
- By default, this will render all results in a JSON array. If the container and image have the same name, this command returns the container JSON.`
+ By default, this will render all results in a JSON array.`
_podInspectCommand = &cobra.Command{
Use: "inspect [flags] POD",
@@ -34,7 +34,7 @@ func init() {
podInspectCommand.SetHelpTemplate(HelpTemplate())
podInspectCommand.SetUsageTemplate(UsageTemplate())
flags := podInspectCommand.Flags()
- flags.BoolVarP(&podInspectCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
+ flags.BoolVarP(&podInspectCommand.Latest, "latest", "l", false, "Act on the latest pod podman is aware of")
markFlagHiddenForRemoteClient("latest", flags)
}
@@ -44,6 +44,11 @@ func podInspectCmd(c *cliconfig.PodInspectValues) error {
pod *adapter.Pod
)
args := c.InputArgs
+
+ if len(args) < 1 && !c.Latest {
+ return errors.Errorf("you must provide the name or id of a pod")
+ }
+
runtime, err := adapter.GetRuntime(&c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
diff --git a/cmd/podman/pod_kill.go b/cmd/podman/pod_kill.go
index ebd7db762..c538674a4 100644
--- a/cmd/podman/pod_kill.go
+++ b/cmd/podman/pod_kill.go
@@ -6,6 +6,7 @@ import (
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/pkg/adapter"
+ "github.com/containers/libpod/pkg/rootless"
"github.com/docker/docker/pkg/signal"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -48,6 +49,7 @@ func init() {
// podKillCmd kills one or more pods with a signal
func podKillCmd(c *cliconfig.PodKillValues) error {
+ rootless.SetSkipStorageSetup(true)
runtime, err := adapter.GetRuntime(&c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
diff --git a/cmd/podman/pod_restart.go b/cmd/podman/pod_restart.go
index 0765b98db..9c8d28424 100644
--- a/cmd/podman/pod_restart.go
+++ b/cmd/podman/pod_restart.go
@@ -2,9 +2,11 @@ package main
import (
"fmt"
+ "os"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/pkg/adapter"
+ "github.com/containers/libpod/pkg/rootless"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -46,12 +48,24 @@ func init() {
func podRestartCmd(c *cliconfig.PodRestartValues) error {
var lastError error
+ if os.Geteuid() != 0 {
+ rootless.SetSkipStorageSetup(true)
+ }
runtime, err := adapter.GetRuntime(&c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
defer runtime.Shutdown(false)
+ if rootless.IsRootless() {
+ var err error
+
+ c.InputArgs, c.All, c.Latest, err = joinPodNS(runtime, c.All, c.Latest, c.InputArgs)
+ if err != nil {
+ return err
+ }
+ }
+
restartIDs, conErrors, restartErrors := runtime.RestartPods(getContext(), c)
for _, p := range restartIDs {
diff --git a/cmd/podman/pod_stats.go b/cmd/podman/pod_stats.go
index 701051938..e8ff322ce 100644
--- a/cmd/podman/pod_stats.go
+++ b/cmd/podman/pod_stats.go
@@ -25,7 +25,7 @@ var (
podStatsDescription = `For each specified pod this command will display percentage of CPU, memory, network I/O, block I/O and PIDs for containers in one the pods.`
_podStatsCommand = &cobra.Command{
- Use: "stats [flags] POD [POD...]",
+ Use: "stats [flags] [POD...]",
Short: "Display a live stream of resource usage statistics for the containers in one or more pods",
Long: podStatsDescription,
RunE: func(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/pod_top.go b/cmd/podman/pod_top.go
index c9a6d8822..f65d66df6 100644
--- a/cmd/podman/pod_top.go
+++ b/cmd/podman/pod_top.go
@@ -9,6 +9,7 @@ import (
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/rootless"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@@ -53,6 +54,10 @@ func podTopCmd(c *cliconfig.PodTopValues) error {
)
args := c.InputArgs
+ if os.Geteuid() != 0 {
+ rootless.SetSkipStorageSetup(true)
+ }
+
if c.ListDescriptors {
descriptors, err := libpod.GetContainerPidInformationDescriptors()
if err != nil {
@@ -77,6 +82,27 @@ func podTopCmd(c *cliconfig.PodTopValues) error {
} else {
descriptors = args[1:]
}
+
+ if os.Geteuid() != 0 {
+ var pod *adapter.Pod
+ var err error
+ if c.Latest {
+ pod, err = runtime.GetLatestPod()
+ } else {
+ pod, err = runtime.LookupPod(c.InputArgs[0])
+ }
+ if err != nil {
+ return errors.Wrapf(err, "unable to lookup requested container")
+ }
+ became, ret, err := runtime.JoinOrCreateRootlessPod(pod)
+ if err != nil {
+ return err
+ }
+ if became {
+ os.Exit(ret)
+ }
+ }
+
w := tabwriter.NewWriter(os.Stdout, 5, 1, 3, ' ', 0)
psOutput, err := runtime.PodTop(c, descriptors)
if err != nil {
diff --git a/cmd/podman/ps.go b/cmd/podman/ps.go
index de6966c3b..ad942da2e 100644
--- a/cmd/podman/ps.go
+++ b/cmd/podman/ps.go
@@ -17,6 +17,7 @@ import (
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/pkg/util"
"github.com/cri-o/ocicni/pkg/ocicni"
"github.com/docker/go-units"
@@ -200,6 +201,9 @@ func init() {
}
func psCmd(c *cliconfig.PsValues) error {
+ if os.Geteuid() != 0 {
+ rootless.SetSkipStorageSetup(true)
+ }
if c.Bool("trace") {
span, _ := opentracing.StartSpanFromContext(Ctx, "psCmd")
defer span.Finish()
diff --git a/cmd/podman/pull.go b/cmd/podman/pull.go
index 7986d5530..8888c5e28 100644
--- a/cmd/podman/pull.go
+++ b/cmd/podman/pull.go
@@ -52,7 +52,7 @@ func init() {
flags.StringVar(&pullCommand.Creds, "creds", "", "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry")
flags.BoolVarP(&pullCommand.Quiet, "quiet", "q", false, "Suppress output information when pulling images")
flags.StringVar(&pullCommand.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)")
- flags.BoolVar(&pullCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries (default: true)")
+ flags.BoolVar(&pullCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries")
}
diff --git a/cmd/podman/push.go b/cmd/podman/push.go
index afc385527..a1dac24ae 100644
--- a/cmd/podman/push.go
+++ b/cmd/podman/push.go
@@ -54,7 +54,7 @@ func init() {
flags.BoolVar(&pushCommand.RemoveSignatures, "remove-signatures", false, "Discard any pre-existing signatures in the image")
flags.StringVar(&pushCommand.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)")
flags.StringVar(&pushCommand.SignBy, "sign-by", "", "Add a signature at the destination using the specified key")
- flags.BoolVar(&pushCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries (default: true)")
+ flags.BoolVar(&pushCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries")
}
func pushCmd(c *cliconfig.PushValues) error {
diff --git a/cmd/podman/restart.go b/cmd/podman/restart.go
index 341cbf978..e6a6d8434 100644
--- a/cmd/podman/restart.go
+++ b/cmd/podman/restart.go
@@ -1,7 +1,6 @@
package main
import (
- "fmt"
"os"
"github.com/containers/libpod/cmd/podman/cliconfig"
@@ -61,6 +60,15 @@ func restartCmd(c *cliconfig.RestartValues) error {
if os.Geteuid() != 0 {
rootless.SetSkipStorageSetup(true)
}
+ if rootless.IsRootless() {
+ // If we are in the re-execed rootless environment,
+ // override the arg to deal only with one container.
+ if os.Geteuid() == 0 {
+ c.All = false
+ c.Latest = false
+ c.InputArgs = []string{rootless.Argument()}
+ }
+ }
args := c.InputArgs
runOnly := c.Running
@@ -107,6 +115,20 @@ func restartCmd(c *cliconfig.RestartValues) error {
}
}
+ if os.Geteuid() != 0 {
+ // In rootless mode we can deal with one container at at time.
+ for _, c := range restartContainers {
+ _, ret, err := joinContainerOrCreateRootlessUserNS(runtime, c)
+ if err != nil {
+ return err
+ }
+ if ret != 0 {
+ os.Exit(ret)
+ }
+ }
+ os.Exit(0)
+ }
+
maxWorkers := shared.Parallelize("restart")
if c.GlobalIsSet("max-workers") {
maxWorkers = c.GlobalFlags.MaxWorks
@@ -114,22 +136,6 @@ func restartCmd(c *cliconfig.RestartValues) error {
logrus.Debugf("Setting maximum workers to %d", maxWorkers)
- if rootless.IsRootless() {
- // With rootless containers we cannot really restart an existing container
- // as we would need to join the mount namespace as well to be able to reuse
- // the storage.
- if err := stopRootlessContainers(restartContainers, timeout, useTimeout, maxWorkers); err != nil {
- return err
- }
- became, ret, err := rootless.BecomeRootInUserNS()
- if err != nil {
- return err
- }
- if became {
- os.Exit(ret)
- }
- }
-
// We now have a slice of all the containers to be restarted. Iterate them to
// create restart Funcs with a timeout as needed
for _, ctr := range restartContainers {
@@ -152,46 +158,3 @@ func restartCmd(c *cliconfig.RestartValues) error {
restartErrors, errCount := shared.ParallelExecuteWorkerPool(maxWorkers, restartFuncs)
return printParallelOutput(restartErrors, errCount)
}
-
-func stopRootlessContainers(stopContainers []*libpod.Container, timeout uint, useTimeout bool, maxWorkers int) error {
- var stopFuncs []shared.ParallelWorkerInput
- for _, ctr := range stopContainers {
- state, err := ctr.State()
- if err != nil {
- return err
- }
- if state != libpod.ContainerStateRunning {
- continue
- }
-
- ctrTimeout := ctr.StopTimeout()
- if useTimeout {
- ctrTimeout = timeout
- }
-
- c := ctr
- f := func() error {
- return c.StopWithTimeout(ctrTimeout)
- }
-
- stopFuncs = append(stopFuncs, shared.ParallelWorkerInput{
- ContainerID: c.ID(),
- ParallelFunc: f,
- })
-
- restartErrors, errCount := shared.ParallelExecuteWorkerPool(maxWorkers, stopFuncs)
- var lastError error
- for _, result := range restartErrors {
- if result != nil {
- if errCount > 1 {
- fmt.Println(result.Error())
- }
- lastError = result
- }
- }
- if lastError != nil {
- return lastError
- }
- }
- return nil
-}
diff --git a/cmd/podman/rm.go b/cmd/podman/rm.go
index 56aaae9eb..253771e14 100644
--- a/cmd/podman/rm.go
+++ b/cmd/podman/rm.go
@@ -108,6 +108,7 @@ func rmCmd(c *cliconfig.RmValues) error {
c.Latest = false
c.InputArgs = []string{rootless.Argument()}
} else {
+ exitCode = 0
var containers []*libpod.Container
if c.All {
containers, err = runtime.GetContainers()
@@ -121,6 +122,10 @@ func rmCmd(c *cliconfig.RmValues) error {
for _, c := range c.InputArgs {
container, err = runtime.LookupContainer(c)
if err != nil {
+ if errors.Cause(err) == libpod.ErrNoSuchCtr {
+ exitCode = 1
+ continue
+ }
return err
}
containers = append(containers, container)
@@ -136,7 +141,7 @@ func rmCmd(c *cliconfig.RmValues) error {
os.Exit(ret)
}
}
- os.Exit(0)
+ os.Exit(exitCode)
}
}
@@ -195,5 +200,10 @@ func rmCmd(c *cliconfig.RmValues) error {
exitCode = 1
}
}
+
+ if failureCnt > 0 {
+ exitCode = 125
+ }
+
return err
}
diff --git a/cmd/podman/run.go b/cmd/podman/run.go
index a92d5d3db..32e7b3510 100644
--- a/cmd/podman/run.go
+++ b/cmd/podman/run.go
@@ -44,7 +44,7 @@ func init() {
runCommand.SetUsageTemplate(UsageTemplate())
flags := runCommand.Flags()
flags.SetInterspersed(false)
- flags.Bool("sig-proxy", true, "Proxy received signals to the process (default true)")
+ flags.Bool("sig-proxy", true, "Proxy received signals to the process")
getCreateFlags(&runCommand.PodmanCommand)
}
diff --git a/cmd/podman/runlabel.go b/cmd/podman/runlabel.go
index 68621e095..f79aa8b0e 100644
--- a/cmd/podman/runlabel.go
+++ b/cmd/podman/runlabel.go
@@ -10,9 +10,11 @@ import (
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/cmd/podman/shared"
+ "github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/utils"
"github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
@@ -45,6 +47,7 @@ func init() {
flags.StringVar(&runlabelCommand.CertDir, "cert-dir", "", "`Pathname` of a directory containing TLS certificates and keys")
flags.StringVar(&runlabelCommand.Creds, "creds", "", "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry")
flags.BoolVar(&runlabelCommand.Display, "display", false, "Preview the command that the label would run")
+ flags.BoolVar(&runlabelCommand.Replace, "replace", false, "Replace existing container with a new one from the image")
flags.StringVar(&runlabelCommand.Name, "name", "", "Assign a name to the container")
flags.StringVar(&runlabelCommand.Opt1, "opt1", "", "Optional parameter to pass for install")
@@ -57,7 +60,7 @@ func init() {
flags.BoolP("pull", "p", false, "Pull the image if it does not exist locally prior to executing the label contents")
flags.BoolVarP(&runlabelCommand.Quiet, "quiet", "q", false, "Suppress output information when installing images")
flags.StringVar(&runlabelCommand.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)")
- flags.BoolVar(&runlabelCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries (default: true)")
+ flags.BoolVar(&runlabelCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries")
flags.MarkDeprecated("pull", "podman will pull if not found in local storage")
}
@@ -146,10 +149,33 @@ func runlabelCmd(c *cliconfig.RunlabelValues) error {
return err
}
if !c.Quiet {
- fmt.Printf("Command: %s\n", strings.Join(cmd, " "))
+ fmt.Printf("command: %s\n", strings.Join(cmd, " "))
if c.Display {
return nil
}
}
+
+ // If container already exists && --replace given -- Nuke it
+ if c.Replace {
+ for i, entry := range cmd {
+ if entry == "--name" {
+ name := cmd[i+1]
+ ctr, err := runtime.LookupContainer(name)
+ if err != nil {
+ if errors.Cause(err) != libpod.ErrNoSuchCtr {
+ logrus.Debugf("Error occurred searching for container %s: %s", name, err.Error())
+ return err
+ }
+ } else {
+ logrus.Debugf("Runlabel --replace option given. Container %s will be deleted. The new container will be named %s", ctr.ID(), name)
+ if err := runtime.RemoveContainer(ctx, ctr, true, false); err != nil {
+ return err
+ }
+ }
+ break
+ }
+ }
+ }
+
return utils.ExecCmdWithStdStreams(stdIn, stdOut, stdErr, env, cmd[0], cmd[1:]...)
}
diff --git a/cmd/podman/save.go b/cmd/podman/save.go
index df016b069..c10679740 100644
--- a/cmd/podman/save.go
+++ b/cmd/podman/save.go
@@ -58,7 +58,7 @@ func init() {
flags := saveCommand.Flags()
flags.BoolVar(&saveCommand.Compress, "compress", false, "Compress tarball image layers when saving to a directory using the 'dir' transport. (default is same compression type as source)")
flags.StringVar(&saveCommand.Format, "format", v2s2Archive, "Save image to oci-archive, oci-dir (directory with oci manifest type), docker-archive, docker-dir (directory with v2s2 manifest type)")
- flags.StringVarP(&saveCommand.Output, "output", "o", "/dev/stdout", "Write to a file, default is STDOUT")
+ flags.StringVarP(&saveCommand.Output, "output", "o", "", "Write to a specified file (default: stdout, which must be redirected)")
flags.BoolVarP(&saveCommand.Quiet, "quiet", "q", false, "Suppress the output")
}
@@ -79,14 +79,14 @@ func saveCmd(c *cliconfig.SaveValues) error {
return errors.Errorf("--compress can only be set when --format is either 'oci-dir' or 'docker-dir'")
}
- output := c.Output
- if output == "/dev/stdout" {
+ if len(c.Output) == 0 {
fi := os.Stdout
if logrus.IsTerminal(fi) {
return errors.Errorf("refusing to save to terminal. Use -o flag or redirect")
}
+ c.Output = "/dev/stdout"
}
- if err := parse.ValidateFileName(output); err != nil {
+ if err := parse.ValidateFileName(c.Output); err != nil {
return err
}
return runtime.SaveImage(getContext(), c)
diff --git a/cmd/podman/search.go b/cmd/podman/search.go
index 25f5a98b7..a10b9d419 100644
--- a/cmd/podman/search.go
+++ b/cmd/podman/search.go
@@ -1,6 +1,7 @@
package main
import (
+ "reflect"
"strings"
"github.com/containers/buildah/pkg/formats"
@@ -46,7 +47,7 @@ func init() {
flags.StringVar(&searchCommand.Format, "format", "", "Change the output format to a Go template")
flags.IntVar(&searchCommand.Limit, "limit", 0, "Limit the number of results")
flags.BoolVar(&searchCommand.NoTrunc, "no-trunc", false, "Do not truncate the output")
- flags.BoolVar(&searchCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries (default: true)")
+ flags.BoolVar(&searchCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries")
}
func searchCmd(c *cliconfig.SearchValues) error {
@@ -79,7 +80,10 @@ func searchCmd(c *cliconfig.SearchValues) error {
return err
}
format := genSearchFormat(c.Format)
- out := formats.StdoutTemplateArray{Output: searchToGeneric(results), Template: format, Fields: results[0].HeaderMap()}
+ if len(results) == 0 {
+ return nil
+ }
+ out := formats.StdoutTemplateArray{Output: searchToGeneric(results), Template: format, Fields: genSearchOutputMap()}
formats.Writer(out).Out()
return nil
}
@@ -99,3 +103,16 @@ func searchToGeneric(params []image.SearchResult) (genericParams []interface{})
}
return genericParams
}
+
+func genSearchOutputMap() map[string]string {
+ io := image.SearchResult{}
+ v := reflect.Indirect(reflect.ValueOf(io))
+ values := make(map[string]string)
+
+ for i := 0; i < v.NumField(); i++ {
+ key := v.Type().Field(i).Name
+ value := key
+ values[key] = strings.ToUpper(splitCamelCase(value))
+ }
+ return values
+}
diff --git a/cmd/podman/shared/container.go b/cmd/podman/shared/container.go
index 41950928e..6826191c5 100644
--- a/cmd/podman/shared/container.go
+++ b/cmd/podman/shared/container.go
@@ -3,11 +3,11 @@ package shared
import (
"context"
"fmt"
- "github.com/google/shlex"
"io"
"os"
"path/filepath"
"regexp"
+ "sort"
"strconv"
"strings"
"sync"
@@ -21,6 +21,7 @@ import (
"github.com/containers/libpod/pkg/util"
"github.com/cri-o/ocicni/pkg/ocicni"
"github.com/docker/go-units"
+ "github.com/google/shlex"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -583,18 +584,93 @@ func getCgroup(spec *specs.Spec) string {
return cgroup
}
+func comparePorts(i, j ocicni.PortMapping) bool {
+ if i.ContainerPort != j.ContainerPort {
+ return i.ContainerPort < j.ContainerPort
+ }
+
+ if i.HostIP != j.HostIP {
+ return i.HostIP < j.HostIP
+ }
+
+ if i.HostPort != j.HostPort {
+ return i.HostPort < j.HostPort
+ }
+
+ return i.Protocol < j.Protocol
+}
+
+// returns the group as <IP:startPort:lastPort->startPort:lastPort/Proto>
+// e.g 0.0.0.0:1000-1006->1000-1006/tcp
+func formatGroup(key string, start, last int32) string {
+ parts := strings.Split(key, "/")
+ groupType := parts[0]
+ var ip string
+ if len(parts) > 1 {
+ ip = parts[0]
+ groupType = parts[1]
+ }
+ group := strconv.Itoa(int(start))
+ if start != last {
+ group = fmt.Sprintf("%s-%d", group, last)
+ }
+ if ip != "" {
+ group = fmt.Sprintf("%s:%s->%s", ip, group, group)
+ }
+ return fmt.Sprintf("%s/%s", group, groupType)
+}
+
// portsToString converts the ports used to a string of the from "port1, port2"
+// also groups continuous list of ports in readable format.
func portsToString(ports []ocicni.PortMapping) string {
+ type portGroup struct {
+ first int32
+ last int32
+ }
var portDisplay []string
if len(ports) == 0 {
return ""
}
+ //Sort the ports, so grouping continuous ports become easy.
+ sort.Slice(ports, func(i, j int) bool {
+ return comparePorts(ports[i], ports[j])
+ })
+
+ // portGroupMap is used for grouping continuous ports
+ portGroupMap := make(map[string]*portGroup)
+ var groupKeyList []string
+
for _, v := range ports {
+
hostIP := v.HostIP
if hostIP == "" {
hostIP = "0.0.0.0"
}
- portDisplay = append(portDisplay, fmt.Sprintf("%s:%d->%d/%s", hostIP, v.HostPort, v.ContainerPort, v.Protocol))
+ // if hostPort and containerPort are not same, consider as individual port.
+ if v.ContainerPort != v.HostPort {
+ portDisplay = append(portDisplay, fmt.Sprintf("%s:%d->%d/%s", hostIP, v.HostPort, v.ContainerPort, v.Protocol))
+ continue
+ }
+
+ portMapKey := fmt.Sprintf("%s/%s", hostIP, v.Protocol)
+
+ portgroup, ok := portGroupMap[portMapKey]
+ if !ok {
+ portGroupMap[portMapKey] = &portGroup{first: v.ContainerPort, last: v.ContainerPort}
+ // this list is required to travese portGroupMap
+ groupKeyList = append(groupKeyList, portMapKey)
+ continue
+ }
+
+ if portgroup.last == (v.ContainerPort - 1) {
+ portgroup.last = v.ContainerPort
+ continue
+ }
+ }
+ // for each portMapKey, format group list and appned to output string
+ for _, portKey := range groupKeyList {
+ group := portGroupMap[portKey]
+ portDisplay = append(portDisplay, formatGroup(portKey, group.first, group.last))
}
return strings.Join(portDisplay, ", ")
}
diff --git a/cmd/podman/shared/create.go b/cmd/podman/shared/create.go
index 32a80e9f9..55eb3ce83 100644
--- a/cmd/podman/shared/create.go
+++ b/cmd/podman/shared/create.go
@@ -499,7 +499,7 @@ func ParseCreateOpts(ctx context.Context, c *cliconfig.PodmanCommand, runtime *l
}
}
}
- if err := parse.ReadKVStrings(env, c.StringSlice("env-file"), c.StringSlice("env")); err != nil {
+ if err := parse.ReadKVStrings(env, c.StringSlice("env-file"), c.StringArray("env")); err != nil {
return nil, errors.Wrapf(err, "unable to process environment variables")
}
diff --git a/cmd/podman/start.go b/cmd/podman/start.go
index e942c1ccd..cf406cf66 100644
--- a/cmd/podman/start.go
+++ b/cmd/podman/start.go
@@ -41,7 +41,7 @@ func init() {
flags.StringVar(&startCommand.DetachKeys, "detach-keys", "", "Override the key sequence for detaching a container. Format is a single character [a-Z] or ctrl-<value> where <value> is one of: a-z, @, ^, [, , or _")
flags.BoolVarP(&startCommand.Interactive, "interactive", "i", false, "Keep STDIN open even if not attached")
flags.BoolVarP(&startCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
- flags.BoolVar(&startCommand.SigProxy, "sig-proxy", true, "Proxy received signals to the process (default true if attaching, false otherwise)")
+ flags.BoolVar(&startCommand.SigProxy, "sig-proxy", false, "Proxy received signals to the process (default true if attaching, false otherwise)")
markFlagHiddenForRemoteClient("latest", flags)
}
@@ -62,14 +62,10 @@ func startCmd(c *cliconfig.StartValues) error {
return errors.Errorf("you cannot start and attach multiple containers at once")
}
- sigProxy := c.SigProxy
+ sigProxy := c.SigProxy || attach
if sigProxy && !attach {
- if c.Flag("sig-proxy").Changed {
- return errors.Wrapf(libpod.ErrInvalidArg, "you cannot use sig-proxy without --attach")
- } else {
- sigProxy = false
- }
+ return errors.Wrapf(libpod.ErrInvalidArg, "you cannot use sig-proxy without --attach")
}
runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
diff --git a/cmd/podman/tree.go b/cmd/podman/tree.go
index ebda18cdb..c56e35aef 100644
--- a/cmd/podman/tree.go
+++ b/cmd/podman/tree.go
@@ -23,7 +23,7 @@ var (
treeDescription = "Prints layer hierarchy of an image in a tree format"
_treeCommand = &cobra.Command{
- Use: "tree",
+ Use: "tree [flags] IMAGE",
Short: treeDescription,
Long: treeDescription,
RunE: func(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/umount.go b/cmd/podman/umount.go
index c57d5794c..a938c7c38 100644
--- a/cmd/podman/umount.go
+++ b/cmd/podman/umount.go
@@ -31,7 +31,7 @@ var (
return umountCmd(&umountCommand)
},
Args: func(cmd *cobra.Command, args []string) error {
- return checkAllAndLatest(cmd, args, true)
+ return checkAllAndLatest(cmd, args, false)
},
Example: `podman umount ctrID
podman umount ctrID1 ctrID2 ctrID3
diff --git a/cmd/podman/varlink/io.podman.varlink b/cmd/podman/varlink/io.podman.varlink
index 791790e2e..517a7a2a1 100644
--- a/cmd/podman/varlink/io.podman.varlink
+++ b/cmd/podman/varlink/io.podman.varlink
@@ -19,6 +19,14 @@ type StringResponse (
message: string
)
+type LogLine (
+ device: string,
+ parseLogType : string,
+ time: string,
+ msg: string,
+ cid: string
+)
+
# ContainerChanges describes the return struct for ListContainerChanges
type ContainerChanges (
changed: []string,
@@ -522,6 +530,8 @@ method ListContainerProcesses(name: string, opts: []string) -> (container: []str
# capability of varlink if the client invokes it.
method GetContainerLogs(name: string) -> (container: []string)
+method GetContainersLogs(names: []string, follow: bool, latest: bool, since: string, tail: int, timestamps: bool) -> (log: LogLine)
+
# ListContainerChanges takes a name or ID of a container and returns changes between the container and
# its base image. It returns a struct of changed, deleted, and added path names.
method ListContainerChanges(name: string) -> (container: ContainerChanges)
diff --git a/cmd/podman/version.go b/cmd/podman/version.go
index 336be892e..31b0b8e82 100644
--- a/cmd/podman/version.go
+++ b/cmd/podman/version.go
@@ -3,6 +3,7 @@ package main
import (
"fmt"
"os"
+ "strings"
"text/tabwriter"
"time"
@@ -43,6 +44,9 @@ func versionCmd(c *cliconfig.VersionValues) error {
versionOutputFormat := c.Format
if versionOutputFormat != "" {
+ if strings.Join(strings.Fields(versionOutputFormat), "") == "{{json.}}" {
+ versionOutputFormat = formats.JSONString
+ }
var out formats.Writer
switch versionOutputFormat {
case formats.JSONString: