summaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'cmd')
-rw-r--r--cmd/podman/attach.go4
-rw-r--r--cmd/podman/build.go33
-rw-r--r--cmd/podman/checkpoint.go12
-rw-r--r--cmd/podman/cleanup.go4
-rw-r--r--cmd/podman/cliconfig/config.go35
-rw-r--r--cmd/podman/cliconfig/create.go1
-rw-r--r--cmd/podman/commands.go5
-rw-r--r--cmd/podman/commit.go72
-rw-r--r--cmd/podman/common.go105
-rw-r--r--cmd/podman/common_libpod.go65
-rw-r--r--cmd/podman/container.go2
-rw-r--r--cmd/podman/containers_prune.go6
-rw-r--r--cmd/podman/cp.go207
-rw-r--r--cmd/podman/create.go15
-rw-r--r--cmd/podman/diff.go24
-rw-r--r--cmd/podman/events.go4
-rw-r--r--cmd/podman/exec.go92
-rw-r--r--cmd/podman/exists.go20
-rw-r--r--cmd/podman/export.go6
-rw-r--r--cmd/podman/generate_kube.go21
-rw-r--r--cmd/podman/generate_systemd.go2
-rw-r--r--cmd/podman/healthcheck_run.go14
-rw-r--r--cmd/podman/history.go17
-rw-r--r--cmd/podman/imagefilters/filters.go10
-rw-r--r--cmd/podman/images.go53
-rw-r--r--cmd/podman/images_prune.go2
-rw-r--r--cmd/podman/import.go10
-rw-r--r--cmd/podman/info.go14
-rw-r--r--cmd/podman/init.go2
-rw-r--r--cmd/podman/inspect.go54
-rw-r--r--cmd/podman/kill.go2
-rw-r--r--cmd/podman/libpodruntime/runtime.go22
-rw-r--r--cmd/podman/load.go4
-rw-r--r--cmd/podman/login.go3
-rw-r--r--cmd/podman/logout.go3
-rw-r--r--cmd/podman/logs.go12
-rw-r--r--cmd/podman/main.go12
-rw-r--r--cmd/podman/main_local.go35
-rw-r--r--cmd/podman/main_remote.go49
-rw-r--r--cmd/podman/mount.go2
-rw-r--r--cmd/podman/pause.go11
-rw-r--r--cmd/podman/platform_linux.go12
-rw-r--r--cmd/podman/play_kube.go312
-rw-r--r--cmd/podman/pod_create.go17
-rw-r--r--cmd/podman/pod_inspect.go2
-rw-r--r--cmd/podman/pod_kill.go4
-rw-r--r--cmd/podman/pod_pause.go4
-rw-r--r--cmd/podman/pod_ps.go29
-rw-r--r--cmd/podman/pod_restart.go4
-rw-r--r--cmd/podman/pod_rm.go2
-rw-r--r--cmd/podman/pod_start.go2
-rw-r--r--cmd/podman/pod_stats.go46
-rw-r--r--cmd/podman/pod_stop.go2
-rw-r--r--cmd/podman/pod_top.go18
-rw-r--r--cmd/podman/pod_unpause.go4
-rw-r--r--cmd/podman/pods_prune.go5
-rw-r--r--cmd/podman/port.go5
-rw-r--r--cmd/podman/ps.go178
-rw-r--r--cmd/podman/pull.go9
-rw-r--r--cmd/podman/push.go7
-rw-r--r--cmd/podman/refresh.go2
-rw-r--r--cmd/podman/remoteclientconfig/config.go21
-rw-r--r--cmd/podman/remoteclientconfig/config_darwin.go12
-rw-r--r--cmd/podman/remoteclientconfig/config_linux.go12
-rw-r--r--cmd/podman/remoteclientconfig/config_windows.go12
-rw-r--r--cmd/podman/remoteclientconfig/configfile.go64
-rw-r--r--cmd/podman/remoteclientconfig/configfile_test.go201
-rw-r--r--cmd/podman/remoteclientconfig/errors.go14
-rw-r--r--cmd/podman/restart.go12
-rw-r--r--cmd/podman/restore.go48
-rw-r--r--cmd/podman/rm.go15
-rw-r--r--cmd/podman/rmi.go6
-rw-r--r--cmd/podman/run.go6
-rw-r--r--cmd/podman/runlabel.go22
-rw-r--r--cmd/podman/save.go6
-rw-r--r--cmd/podman/search.go11
-rw-r--r--cmd/podman/shared/container.go257
-rw-r--r--cmd/podman/shared/create.go109
-rw-r--r--cmd/podman/shared/create_cli.go6
-rw-r--r--cmd/podman/shared/funcs.go15
-rw-r--r--cmd/podman/shared/intermediate.go14
-rw-r--r--cmd/podman/shared/parse/parse.go29
-rw-r--r--cmd/podman/shared/pod.go13
-rw-r--r--cmd/podman/sign.go2
-rw-r--r--cmd/podman/start.go8
-rw-r--r--cmd/podman/stats.go18
-rw-r--r--cmd/podman/stop.go8
-rw-r--r--cmd/podman/system_df.go42
-rw-r--r--cmd/podman/system_prune.go26
-rw-r--r--cmd/podman/tag.go2
-rw-r--r--cmd/podman/top.go17
-rw-r--r--cmd/podman/tree.go12
-rw-r--r--cmd/podman/trust_set_show.go29
-rw-r--r--cmd/podman/umount.go2
-rw-r--r--cmd/podman/unpause.go11
-rw-r--r--cmd/podman/unshare.go15
-rw-r--r--cmd/podman/utils.go48
-rw-r--r--cmd/podman/varlink.go2
-rw-r--r--cmd/podman/varlink/io.podman.varlink48
-rw-r--r--cmd/podman/version.go20
-rw-r--r--cmd/podman/volume_create.go2
-rw-r--r--cmd/podman/volume_inspect.go2
-rw-r--r--cmd/podman/volume_ls.go4
-rw-r--r--cmd/podman/volume_prune.go2
-rw-r--r--cmd/podman/volume_rm.go2
-rw-r--r--cmd/podman/wait.go2
106 files changed, 1535 insertions, 1424 deletions
diff --git a/cmd/podman/attach.go b/cmd/podman/attach.go
index 37f8afbad..b78633ed6 100644
--- a/cmd/podman/attach.go
+++ b/cmd/podman/attach.go
@@ -31,7 +31,7 @@ func init() {
attachCommand.SetHelpTemplate(HelpTemplate())
attachCommand.SetUsageTemplate(UsageTemplate())
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.StringVar(&attachCommand.DetachKeys, "detach-keys", "", "Override 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(&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")
flags.BoolVarP(&attachCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
@@ -51,6 +51,6 @@ func attachCmd(c *cliconfig.AttachValues) error {
if err != nil {
return errors.Wrapf(err, "error creating runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
return runtime.Attach(getContext(), c)
}
diff --git a/cmd/podman/build.go b/cmd/podman/build.go
index 6e70c6540..14ac51889 100644
--- a/cmd/podman/build.go
+++ b/cmd/podman/build.go
@@ -57,14 +57,20 @@ func init() {
budFlags := buildahcli.GetBudFlags(&budFlagsValues)
flag := budFlags.Lookup("pull")
- flag.Value.Set("true")
+ if err := flag.Value.Set("true"); err != nil {
+ logrus.Error("unable to set pull flag to true")
+ }
flag.DefValue = "true"
layerFlags := buildahcli.GetLayerFlags(&layerValues)
flag = layerFlags.Lookup("layers")
- flag.Value.Set(useLayers())
- flag.DefValue = (useLayers())
+ if err := flag.Value.Set(useLayers()); err != nil {
+ logrus.Error("unable to set uselayers")
+ }
+ flag.DefValue = useLayers()
flag = layerFlags.Lookup("force-rm")
- flag.Value.Set("true")
+ if err := flag.Value.Set("true"); err != nil {
+ logrus.Error("unable to set force-rm flag to true")
+ }
flag.DefValue = "true"
fromAndBugFlags := buildahcli.GetFromAndBudFlags(&fromAndBudValues, &userNSValues, &namespaceValues)
@@ -72,7 +78,7 @@ func init() {
flags.AddFlagSet(&budFlags)
flags.AddFlagSet(&layerFlags)
flags.AddFlagSet(&fromAndBugFlags)
- flags.MarkHidden("signature-policy")
+ markFlagHidden(flags, "signature-policy")
}
func getDockerfiles(files []string) []string {
@@ -95,6 +101,10 @@ func getNsValues(c *cliconfig.BuildValues) ([]buildah.NamespaceOption, error) {
Name: string(specs.NetworkNamespace),
Host: true,
})
+ } else if c.Network == "container" {
+ ret = append(ret, buildah.NamespaceOption{
+ Name: string(specs.NetworkNamespace),
+ })
} else if c.Network[0] == '/' {
ret = append(ret, buildah.NamespaceOption{
Name: string(specs.NetworkNamespace),
@@ -177,7 +187,6 @@ func buildCmd(c *cliconfig.BuildValues) error {
}
contextDir = absDir
}
- cliArgs = Tail(cliArgs)
} else {
// No context directory or URL was specified. Try to use the
// home of the first locally-available Dockerfile.
@@ -218,7 +227,7 @@ func buildCmd(c *cliconfig.BuildValues) error {
}
// end from buildah
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
var stdout, stderr, reporter *os.File
stdout = os.Stdout
@@ -303,16 +312,6 @@ func buildCmd(c *cliconfig.BuildValues) error {
return runtime.Build(getContext(), c, options, dockerfiles)
}
-// Tail returns a string slice after the first element unless there are
-// not enough elements, then it returns an empty slice. This is to replace
-// the urfavecli Tail method for args
-func Tail(a []string) []string {
- if len(a) >= 2 {
- return []string(a)[1:]
- }
- return []string{}
-}
-
// useLayers returns false if BUILDAH_LAYERS is set to "0" or "false"
// otherwise it returns true
func useLayers() string {
diff --git a/cmd/podman/checkpoint.go b/cmd/podman/checkpoint.go
index 234d683bb..22cdb1f39 100644
--- a/cmd/podman/checkpoint.go
+++ b/cmd/podman/checkpoint.go
@@ -2,7 +2,6 @@ package main
import (
"github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/adapter"
"github.com/containers/libpod/pkg/rootless"
"github.com/pkg/errors"
@@ -46,6 +45,8 @@ func init() {
flags.BoolVar(&checkpointCommand.TcpEstablished, "tcp-established", false, "Checkpoint a container with established TCP connections")
flags.BoolVarP(&checkpointCommand.All, "all", "a", false, "Checkpoint all running containers")
flags.BoolVarP(&checkpointCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
+ flags.StringVarP(&checkpointCommand.Export, "export", "e", "", "Export the checkpoint image to a tar.gz")
+ flags.BoolVar(&checkpointCommand.IgnoreRootfs, "ignore-rootfs", false, "Do not include root file-system changes when exporting")
markFlagHiddenForRemoteClient("latest", flags)
}
@@ -58,12 +59,7 @@ func checkpointCmd(c *cliconfig.CheckpointValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
- options := libpod.ContainerCheckpointOptions{
- Keep: c.Keep,
- KeepRunning: c.LeaveRunning,
- TCPEstablished: c.TcpEstablished,
- }
- return runtime.Checkpoint(c, options)
+ defer runtime.DeferredShutdown(false)
+ return runtime.Checkpoint(c)
}
diff --git a/cmd/podman/cleanup.go b/cmd/podman/cleanup.go
index 4ff744ae5..c00654162 100644
--- a/cmd/podman/cleanup.go
+++ b/cmd/podman/cleanup.go
@@ -1,3 +1,5 @@
+//+build !remoteclient
+
package main
import (
@@ -50,7 +52,7 @@ func cleanupCmd(c *cliconfig.CleanupValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
ok, failures, err := runtime.CleanupContainers(getContext(), c)
if err != nil {
diff --git a/cmd/podman/cliconfig/config.go b/cmd/podman/cliconfig/config.go
index aaa4513d8..025f40cf6 100644
--- a/cmd/podman/cliconfig/config.go
+++ b/cmd/podman/cliconfig/config.go
@@ -33,9 +33,11 @@ type MainFlags struct {
LogLevel string
TmpDir string
- RemoteUserName string
- RemoteHost string
- VarlinkAddress string
+ RemoteUserName string
+ RemoteHost string
+ VarlinkAddress string
+ ConnectionName string
+ RemoteConfigFilePath string
}
type AttachValues struct {
@@ -89,6 +91,8 @@ type CheckpointValues struct {
TcpEstablished bool
All bool
Latest bool
+ Export string
+ IgnoreRootfs bool
}
type CommitValues struct {
@@ -110,18 +114,20 @@ type DiffValues struct {
PodmanCommand
Archive bool
Format string
+ Latest bool
}
type ExecValues struct {
PodmanCommand
- Env []string
- Privileged bool
- Interfactive bool
- Tty bool
- User string
- Latest bool
- Workdir string
- PreserveFDs int
+ DetachKeys string
+ Env []string
+ Privileged bool
+ Interactive bool
+ Tty bool
+ User string
+ Latest bool
+ Workdir string
+ PreserveFDs int
}
type ImageExistsValues struct {
@@ -142,7 +148,8 @@ type ExportValues struct {
}
type GenerateKubeValues struct {
PodmanCommand
- Service bool
+ Service bool
+ Filename string
}
type GenerateSystemdValues struct {
@@ -426,6 +433,9 @@ type RestoreValues struct {
Keep bool
Latest bool
TcpEstablished bool
+ Import string
+ Name string
+ IgnoreRootfs bool
}
type RmValues struct {
@@ -433,6 +443,7 @@ type RmValues struct {
All bool
Force bool
Latest bool
+ Storage bool
Volumes bool
}
diff --git a/cmd/podman/cliconfig/create.go b/cmd/podman/cliconfig/create.go
index 49ab3d827..5fb2eed10 100644
--- a/cmd/podman/cliconfig/create.go
+++ b/cmd/podman/cliconfig/create.go
@@ -24,4 +24,5 @@ type BuildValues struct {
type CpValues struct {
PodmanCommand
Extract bool
+ Pause bool
}
diff --git a/cmd/podman/commands.go b/cmd/podman/commands.go
index 2ac465b9d..27f3fc214 100644
--- a/cmd/podman/commands.go
+++ b/cmd/podman/commands.go
@@ -11,8 +11,6 @@ const remoteclient = false
// Commands that the local client implements
func getMainCommands() []*cobra.Command {
rootCommands := []*cobra.Command{
- _commitCommand,
- _execCommand,
_playCommand,
_loginCommand,
_logoutCommand,
@@ -20,6 +18,7 @@ func getMainCommands() []*cobra.Command {
_refreshCommand,
_searchCommand,
_statsCommand,
+ _umountCommand,
_unshareCommand,
}
@@ -41,8 +40,6 @@ func getContainerSubCommands() []*cobra.Command {
return []*cobra.Command{
_cleanupCommand,
- _commitCommand,
- _execCommand,
_mountCommand,
_refreshCommand,
_runlabelCommand,
diff --git a/cmd/podman/commit.go b/cmd/podman/commit.go
index 2b38bab35..e98b71514 100644
--- a/cmd/podman/commit.go
+++ b/cmd/podman/commit.go
@@ -2,16 +2,10 @@ package main
import (
"fmt"
- "io"
- "os"
"strings"
- "github.com/containers/buildah"
- "github.com/containers/image/manifest"
"github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/containers/libpod/cmd/podman/libpodruntime"
- "github.com/containers/libpod/libpod"
- "github.com/containers/libpod/libpod/image"
+ "github.com/containers/libpod/pkg/adapter"
"github.com/containers/libpod/pkg/util"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -31,10 +25,13 @@ var (
commitCommand.Remote = remoteclient
return commitCmd(&commitCommand)
},
- Example: `podman commit -q --message "committing container to image" reverent_golick image-commited
- podman commit -q --author "firstName lastName" reverent_golick image-commited
- podman commit -q --pause=false containerID image-commited`,
+ 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`,
}
+
+ // ChangeCmds is the list of valid Changes commands to passed to the Commit call
+ ChangeCmds = []string{"CMD", "ENTRYPOINT", "ENV", "EXPOSE", "LABEL", "ONBUILD", "STOPSIGNAL", "USER", "VOLUME", "WORKDIR"}
)
func init() {
@@ -42,7 +39,7 @@ func init() {
commitCommand.SetHelpTemplate(HelpTemplate())
commitCommand.SetUsageTemplate(UsageTemplate())
flags := commitCommand.Flags()
- flags.StringArrayVarP(&commitCommand.Change, "change", "c", []string{}, fmt.Sprintf("Apply the following possible instructions to the created image (default []): %s", strings.Join(libpod.ChangeCmds, " | ")))
+ flags.StringArrayVarP(&commitCommand.Change, "change", "c", []string{}, fmt.Sprintf("Apply the following possible instructions to the created image (default []): %s", strings.Join(ChangeCmds, " | ")))
flags.StringVarP(&commitCommand.Format, "format", "f", "oci", "`Format` of the image manifest and metadata")
flags.StringVarP(&commitCommand.Message, "message", "m", "", "Set commit message for imported image")
flags.StringVarP(&commitCommand.Author, "author", "a", "", "Set the author for the image committed")
@@ -52,32 +49,17 @@ func init() {
}
func commitCmd(c *cliconfig.CommitValues) error {
- runtime, err := libpodruntime.GetRuntime(getContext(), &c.PodmanCommand)
+ runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
- var (
- writer io.Writer
- mimeType string
- )
args := c.InputArgs
if len(args) != 2 {
return errors.Errorf("you must provide a container name or ID and a target image name")
}
- switch c.Format {
- case "oci":
- mimeType = buildah.OCIv1ImageManifest
- if c.Flag("message").Changed {
- return errors.Errorf("messages are only compatible with the docker image format (-f docker)")
- }
- case "docker":
- mimeType = manifest.DockerV2Schema2MediaType
- default:
- return errors.Errorf("unrecognized image format %q", c.Format)
- }
container := args[0]
reference := args[1]
if c.Flag("change").Changed {
@@ -86,44 +68,16 @@ func commitCmd(c *cliconfig.CommitValues) error {
if len(splitChange) == 1 {
splitChange = strings.Split(strings.ToUpper(change), " ")
}
- if !util.StringInSlice(splitChange[0], libpod.ChangeCmds) {
+ if !util.StringInSlice(splitChange[0], ChangeCmds) {
return errors.Errorf("invalid syntax for --change: %s", change)
}
}
}
- if !c.Quiet {
- writer = os.Stderr
- }
- ctr, err := runtime.LookupContainer(container)
- if err != nil {
- return errors.Wrapf(err, "error looking up container %q", container)
- }
-
- rtc, err := runtime.GetConfig()
- if err != nil {
- return err
- }
-
- sc := image.GetSystemContext(rtc.SignaturePolicyPath, "", false)
- coptions := buildah.CommitOptions{
- SignaturePolicyPath: rtc.SignaturePolicyPath,
- ReportWriter: writer,
- SystemContext: sc,
- PreferredManifestType: mimeType,
- }
- options := libpod.ContainerCommitOptions{
- CommitOptions: coptions,
- Pause: c.Pause,
- IncludeVolumes: c.IncludeVolumes,
- Message: c.Message,
- Changes: c.Change,
- Author: c.Author,
- }
- newImage, err := ctr.Commit(getContext(), reference, options)
+ iid, err := runtime.Commit(getContext(), c, container, reference)
if err != nil {
return err
}
- fmt.Println(newImage.ID())
+ fmt.Println(iid)
return nil
}
diff --git a/cmd/podman/common.go b/cmd/podman/common.go
index 054b01247..1e9092bd6 100644
--- a/cmd/podman/common.go
+++ b/cmd/podman/common.go
@@ -4,14 +4,13 @@ import (
"context"
"fmt"
"os"
- "path/filepath"
"strings"
"github.com/containers/buildah"
"github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/cmd/podman/shared"
+ "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/rootless"
- "github.com/containers/storage"
"github.com/fatih/camelcase"
jsoniter "github.com/json-iterator/go"
"github.com/pkg/errors"
@@ -19,8 +18,7 @@ import (
)
var (
- stores = make(map[storage.Store]struct{})
- json = jsoniter.ConfigCompatibleWithStandardLibrary
+ json = jsoniter.ConfigCompatibleWithStandardLibrary
)
const (
@@ -80,58 +78,6 @@ func commandRunE() func(*cobra.Command, []string) error {
}
}
-// getAllOrLatestContainers tries to return the correct list of containers
-// depending if --all, --latest or <container-id> is used.
-// It requires the Context (c) and the Runtime (runtime). As different
-// commands are using different container state for the --all option
-// the desired state has to be specified in filterState. If no filter
-// is desired a -1 can be used to get all containers. For a better
-// error message, if the filter fails, a corresponding verb can be
-// specified which will then appear in the error message.
-func getAllOrLatestContainers(c *cliconfig.PodmanCommand, runtime *libpod.Runtime, filterState libpod.ContainerStatus, verb string) ([]*libpod.Container, error) {
- var containers []*libpod.Container
- var lastError error
- var err error
- if c.Bool("all") {
- if filterState != -1 {
- var filterFuncs []libpod.ContainerFilter
- filterFuncs = append(filterFuncs, func(c *libpod.Container) bool {
- state, _ := c.State()
- return state == filterState
- })
- containers, err = runtime.GetContainers(filterFuncs...)
- } else {
- containers, err = runtime.GetContainers()
- }
- if err != nil {
- return nil, errors.Wrapf(err, "unable to get %s containers", verb)
- }
- } else if c.Bool("latest") {
- lastCtr, err := runtime.GetLatestContainer()
- if err != nil {
- return nil, errors.Wrapf(err, "unable to get latest container")
- }
- containers = append(containers, lastCtr)
- } else {
- args := c.InputArgs
- for _, i := range args {
- container, err := runtime.LookupContainer(i)
- if err != nil {
- if lastError != nil {
- fmt.Fprintln(os.Stderr, lastError)
- }
- lastError = errors.Wrapf(err, "unable to find container %s", i)
- }
- if container != nil {
- // This is here to make sure this does not return [<nil>] but only nil
- containers = append(containers, container)
- }
- }
- }
-
- return containers, lastError
-}
-
// getContext returns a non-nil, empty context
func getContext() context.Context {
if Ctx != nil {
@@ -164,7 +110,7 @@ func getCreateFlags(c *cliconfig.PodmanCommand) {
"Attach to STDIN, STDOUT or STDERR (default [])",
)
createFlags.String(
- "authfile", getAuthFile(""),
+ "authfile", shared.GetAuthFile(""),
"Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override",
)
createFlags.String(
@@ -184,6 +130,10 @@ func getCreateFlags(c *cliconfig.PodmanCommand) {
"Drop capabilities from the container",
)
createFlags.String(
+ "cgroupns", "host",
+ "cgroup namespace to use",
+ )
+ createFlags.String(
"cgroup-parent", "",
"Optional parent cgroup for the container",
)
@@ -233,7 +183,7 @@ func getCreateFlags(c *cliconfig.PodmanCommand) {
)
createFlags.String(
"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 `_`",
+ "Override 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 `_`",
)
createFlags.StringSlice(
"device", []string{},
@@ -275,6 +225,9 @@ func getCreateFlags(c *cliconfig.PodmanCommand) {
"env", "e", []string{},
"Set environment variables in container",
)
+ createFlags.Bool(
+ "env-host", false, "Use all current host environment variables in container",
+ )
createFlags.StringSlice(
"env-file", []string{},
"Read in a file of environment variables",
@@ -295,23 +248,23 @@ func getCreateFlags(c *cliconfig.PodmanCommand) {
"help", false, "",
)
createFlags.String(
- "healthcheck-command", "",
+ "health-cmd", "",
"set a healthcheck command for the container ('none' disables the existing healthcheck)",
)
createFlags.String(
- "healthcheck-interval", cliconfig.DefaultHealthCheckInterval,
+ "health-interval", cliconfig.DefaultHealthCheckInterval,
"set an interval for the healthchecks (a value of disable results in no automatic timer setup)",
)
createFlags.Uint(
- "healthcheck-retries", cliconfig.DefaultHealthCheckRetries,
+ "health-retries", cliconfig.DefaultHealthCheckRetries,
"the number of retries allowed before a healthcheck is considered to be unhealthy",
)
createFlags.String(
- "healthcheck-start-period", cliconfig.DefaultHealthCheckStartPeriod,
+ "health-start-period", cliconfig.DefaultHealthCheckStartPeriod,
"the initialization time needed for a container to bootstrap",
)
createFlags.String(
- "healthcheck-timeout", cliconfig.DefaultHealthCheckTimeout,
+ "health-timeout", cliconfig.DefaultHealthCheckTimeout,
"the maximum time allowed to complete the healthcheck before an interval is considered failed",
)
createFlags.StringP(
@@ -333,7 +286,7 @@ func getCreateFlags(c *cliconfig.PodmanCommand) {
createFlags.String(
"init-path", "",
// Do not use the Value field for setting the default value to determine user input (i.e., non-empty string)
- fmt.Sprintf("Path to the container-init binary (default: %q)", libpod.DefaultInitPath),
+ fmt.Sprintf("Path to the container-init binary (default: %q)", define.DefaultInitPath),
)
createFlags.BoolP(
"interactive", "i", false,
@@ -472,7 +425,7 @@ func getCreateFlags(c *cliconfig.PodmanCommand) {
"Signal to stop a container. Default is SIGTERM",
)
createFlags.Uint(
- "stop-timeout", libpod.CtrRemoveTimeout,
+ "stop-timeout", define.CtrRemoveTimeout,
"Timeout (in seconds) to stop a container. Default is 10",
)
createFlags.StringSlice(
@@ -496,7 +449,7 @@ func getCreateFlags(c *cliconfig.PodmanCommand) {
"systemd", cliconfig.DefaultSystemD,
"Run container in systemd mode if the command executable is systemd or init",
)
- createFlags.StringSlice(
+ createFlags.StringArray(
"tmpfs", []string{},
"Mount a temporary filesystem (`tmpfs`) into a container (default [])",
)
@@ -554,24 +507,6 @@ func getFormat(c *cliconfig.PodmanCommand) (string, error) {
return "", errors.Errorf("unrecognized image type %q", format)
}
-func getAuthFile(authfile string) string {
- if authfile != "" {
- return authfile
- }
- if remote {
- return ""
- }
- authfile = os.Getenv("REGISTRY_AUTH_FILE")
- if authfile != "" {
- return authfile
- }
- runtimeDir := os.Getenv("XDG_RUNTIME_DIR")
- if runtimeDir != "" {
- return filepath.Join(runtimeDir, "containers/auth.json")
- }
- return ""
-}
-
// scrubServer removes 'http://' or 'https://' from the front of the
// server/registry string if either is there. This will be mostly used
// for user input from 'podman login' and 'podman logout'.
diff --git a/cmd/podman/common_libpod.go b/cmd/podman/common_libpod.go
new file mode 100644
index 000000000..5deea15d3
--- /dev/null
+++ b/cmd/podman/common_libpod.go
@@ -0,0 +1,65 @@
+//build !remoteclient
+
+package main
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/containers/libpod/cmd/podman/cliconfig"
+ "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
+ "github.com/pkg/errors"
+)
+
+// getAllOrLatestContainers tries to return the correct list of containers
+// depending if --all, --latest or <container-id> is used.
+// It requires the Context (c) and the Runtime (runtime). As different
+// commands are using different container state for the --all option
+// the desired state has to be specified in filterState. If no filter
+// is desired a -1 can be used to get all containers. For a better
+// error message, if the filter fails, a corresponding verb can be
+// specified which will then appear in the error message.
+func getAllOrLatestContainers(c *cliconfig.PodmanCommand, runtime *libpod.Runtime, filterState define.ContainerStatus, verb string) ([]*libpod.Container, error) {
+ var containers []*libpod.Container
+ var lastError error
+ var err error
+ if c.Bool("all") {
+ if filterState != -1 {
+ var filterFuncs []libpod.ContainerFilter
+ filterFuncs = append(filterFuncs, func(c *libpod.Container) bool {
+ state, _ := c.State()
+ return state == filterState
+ })
+ containers, err = runtime.GetContainers(filterFuncs...)
+ } else {
+ containers, err = runtime.GetContainers()
+ }
+ if err != nil {
+ return nil, errors.Wrapf(err, "unable to get %s containers", verb)
+ }
+ } else if c.Bool("latest") {
+ lastCtr, err := runtime.GetLatestContainer()
+ if err != nil {
+ return nil, errors.Wrapf(err, "unable to get latest container")
+ }
+ containers = append(containers, lastCtr)
+ } else {
+ args := c.InputArgs
+ for _, i := range args {
+ container, err := runtime.LookupContainer(i)
+ if err != nil {
+ if lastError != nil {
+ fmt.Fprintln(os.Stderr, lastError)
+ }
+ lastError = errors.Wrapf(err, "unable to find container %s", i)
+ }
+ if container != nil {
+ // This is here to make sure this does not return [<nil>] but only nil
+ containers = append(containers, container)
+ }
+ }
+ }
+
+ return containers, lastError
+}
diff --git a/cmd/podman/container.go b/cmd/podman/container.go
index 839ae3a0e..557f5fafa 100644
--- a/cmd/podman/container.go
+++ b/cmd/podman/container.go
@@ -52,10 +52,12 @@ var (
containerCommands = []*cobra.Command{
_attachCommand,
_checkpointCommand,
+ _commitCommand,
_containerExistsCommand,
_contInspectSubCommand,
_cpCommand,
_diffCommand,
+ _execCommand,
_exportCommand,
_createCommand,
_initCommand,
diff --git a/cmd/podman/containers_prune.go b/cmd/podman/containers_prune.go
index b052bda36..b8a84a0e3 100644
--- a/cmd/podman/containers_prune.go
+++ b/cmd/podman/containers_prune.go
@@ -3,7 +3,7 @@ package main
import (
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/shared"
- "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/adapter"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -43,7 +43,7 @@ func pruneContainersCmd(c *cliconfig.PruneContainersValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
maxWorkers := shared.DefaultPoolSize("prune")
if c.GlobalIsSet("max-workers") {
@@ -51,7 +51,7 @@ func pruneContainersCmd(c *cliconfig.PruneContainersValues) error {
}
ok, failures, err := runtime.Prune(getContext(), maxWorkers, c.Force)
if err != nil {
- if errors.Cause(err) == libpod.ErrNoSuchCtr {
+ if errors.Cause(err) == define.ErrNoSuchCtr {
if len(c.InputArgs) > 1 {
exitCode = 125
} else {
diff --git a/cmd/podman/cp.go b/cmd/podman/cp.go
index 8240cc193..bee7d2199 100644
--- a/cmd/podman/cp.go
+++ b/cmd/podman/cp.go
@@ -13,12 +13,15 @@ import (
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
+ "github.com/containers/libpod/pkg/rootless"
"github.com/containers/storage"
"github.com/containers/storage/pkg/archive"
"github.com/containers/storage/pkg/chrootarchive"
"github.com/containers/storage/pkg/idtools"
- digest "github.com/opencontainers/go-digest"
- specs "github.com/opencontainers/runtime-spec/specs-go"
+ securejoin "github.com/cyphar/filepath-securejoin"
+ "github.com/opencontainers/go-digest"
+ "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -49,6 +52,7 @@ func init() {
cpCommand.Command = _cpCommand
flags := cpCommand.Flags()
flags.BoolVar(&cpCommand.Extract, "extract", false, "Extract the tar file into the destination directory.")
+ flags.BoolVar(&cpCommand.Pause, "pause", false, "Pause the container while copying")
cpCommand.SetHelpTemplate(HelpTemplate())
cpCommand.SetUsageTemplate(UsageTemplate())
rootCmd.AddCommand(cpCommand.Command)
@@ -64,13 +68,12 @@ func cpCmd(c *cliconfig.CpValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
- extract := c.Flag("extract").Changed
- return copyBetweenHostAndContainer(runtime, args[0], args[1], extract)
+ return copyBetweenHostAndContainer(runtime, args[0], args[1], c.Extract, c.Pause)
}
-func copyBetweenHostAndContainer(runtime *libpod.Runtime, src string, dest string, extract bool) error {
+func copyBetweenHostAndContainer(runtime *libpod.Runtime, src string, dest string, extract bool, pause bool) error {
srcCtr, srcPath := parsePath(runtime, src)
destCtr, destPath := parsePath(runtime, dest)
@@ -83,7 +86,7 @@ func copyBetweenHostAndContainer(runtime *libpod.Runtime, src string, dest strin
return errors.Errorf("invalid arguments %s, %s you must specify paths", src, dest)
}
ctr := srcCtr
- isFromHostToCtr := (ctr == nil)
+ isFromHostToCtr := ctr == nil
if isFromHostToCtr {
ctr = destCtr
}
@@ -92,7 +95,43 @@ func copyBetweenHostAndContainer(runtime *libpod.Runtime, src string, dest strin
if err != nil {
return err
}
- defer ctr.Unmount(false)
+ defer func() {
+ if err := ctr.Unmount(false); err != nil {
+ logrus.Errorf("unable to umount container '%s': %q", ctr.ID(), err)
+ }
+ }()
+
+ // We can't pause rootless containers.
+ if pause && rootless.IsRootless() {
+ state, err := ctr.State()
+ if err != nil {
+ return err
+ }
+ if state == define.ContainerStateRunning {
+ return errors.Errorf("cannot copy into running rootless container with pause set - pass --pause=false to force copying")
+ }
+ }
+
+ if pause && !rootless.IsRootless() {
+ if err := ctr.Pause(); err != nil {
+ // An invalid state error is fine.
+ // The container isn't running or is already paused.
+ // TODO: We can potentially start the container while
+ // the copy is running, which still allows a race where
+ // malicious code could mess with the symlink.
+ if errors.Cause(err) != define.ErrCtrStateInvalid {
+ return err
+ }
+ } else {
+ // Only add the defer if we actually paused
+ defer func() {
+ if err := ctr.Unpause(); err != nil {
+ logrus.Errorf("Error unpausing container after copying: %v", err)
+ }
+ }()
+ }
+ }
+
user, err := getUser(mountPoint, ctr.User())
if err != nil {
return err
@@ -111,20 +150,63 @@ func copyBetweenHostAndContainer(runtime *libpod.Runtime, src string, dest strin
var glob []string
if isFromHostToCtr {
- if filepath.IsAbs(destPath) {
- destPath = filepath.Join(mountPoint, destPath)
-
+ if isVol, volDestName, volName := isVolumeDestName(destPath, ctr); isVol {
+ path, err := pathWithVolumeMount(ctr, runtime, volDestName, volName, destPath)
+ if err != nil {
+ return errors.Wrapf(err, "error getting destination path from volume %s", volDestName)
+ }
+ destPath = path
+ } else if isBindMount, mount := isBindMountDestName(destPath, ctr); isBindMount {
+ path, err := pathWithBindMountSource(mount, destPath)
+ if err != nil {
+ return errors.Wrapf(err, "error getting destination path from bind mount %s", mount.Destination)
+ }
+ destPath = path
+ } else if filepath.IsAbs(destPath) {
+ cleanedPath, err := securejoin.SecureJoin(mountPoint, destPath)
+ if err != nil {
+ return err
+ }
+ destPath = cleanedPath
} else {
- if err = idtools.MkdirAllAndChownNew(filepath.Join(mountPoint, ctr.WorkingDir()), 0755, hostOwner); err != nil {
+ ctrWorkDir, err := securejoin.SecureJoin(mountPoint, ctr.WorkingDir())
+ if err != nil {
+ return err
+ }
+ if err = idtools.MkdirAllAndChownNew(ctrWorkDir, 0755, hostOwner); err != nil {
return errors.Wrapf(err, "error creating directory %q", destPath)
}
- destPath = filepath.Join(mountPoint, ctr.WorkingDir(), destPath)
+ cleanedPath, err := securejoin.SecureJoin(mountPoint, filepath.Join(ctr.WorkingDir(), destPath))
+ if err != nil {
+ return err
+ }
+ destPath = cleanedPath
}
} else {
- if filepath.IsAbs(srcPath) {
- srcPath = filepath.Join(mountPoint, srcPath)
+ if isVol, volDestName, volName := isVolumeDestName(srcPath, ctr); isVol {
+ path, err := pathWithVolumeMount(ctr, runtime, volDestName, volName, srcPath)
+ if err != nil {
+ return errors.Wrapf(err, "error getting source path from volume %s", volDestName)
+ }
+ srcPath = path
+ } else if isBindMount, mount := isBindMountDestName(srcPath, ctr); isBindMount {
+ path, err := pathWithBindMountSource(mount, srcPath)
+ if err != nil {
+ return errors.Wrapf(err, "error getting source path from bind moutn %s", mount.Destination)
+ }
+ srcPath = path
+ } else if filepath.IsAbs(srcPath) {
+ cleanedPath, err := securejoin.SecureJoin(mountPoint, srcPath)
+ if err != nil {
+ return err
+ }
+ srcPath = cleanedPath
} else {
- srcPath = filepath.Join(mountPoint, ctr.WorkingDir(), srcPath)
+ cleanedPath, err := securejoin.SecureJoin(mountPoint, filepath.Join(ctr.WorkingDir(), srcPath))
+ if err != nil {
+ return err
+ }
+ srcPath = cleanedPath
}
}
glob, err = filepath.Glob(srcPath)
@@ -158,7 +240,7 @@ func copyBetweenHostAndContainer(runtime *libpod.Runtime, src string, dest strin
}
func getUser(mountPoint string, userspec string) (specs.User, error) {
- uid, gid, err := chrootuser.GetUser(mountPoint, userspec)
+ uid, gid, _, err := chrootuser.GetUser(mountPoint, userspec)
u := specs.User{
UID: uid,
GID: gid,
@@ -229,7 +311,7 @@ func copy(src, destPath, dest string, idMappingOpts storage.IDMappingOptions, ch
if err != nil && !os.IsNotExist(err) {
return errors.Wrapf(err, "error checking directory %q", destdir)
}
- destDirIsExist := (err == nil)
+ destDirIsExist := err == nil
if err = os.MkdirAll(destdir, 0755); err != nil {
return errors.Wrapf(err, "error creating directory %q", destdir)
}
@@ -249,20 +331,6 @@ func copy(src, destPath, dest string, idMappingOpts storage.IDMappingOptions, ch
}
return nil
}
- if !archive.IsArchivePath(srcPath) {
- // This srcPath is a file, and either it's not an
- // archive, or we don't care whether or not it's an
- // archive.
- destfi, err := os.Stat(destPath)
- if err != nil {
- if !os.IsNotExist(err) {
- return errors.Wrapf(err, "failed to get stat of dest path %s", destPath)
- }
- }
- if destfi != nil && destfi.IsDir() {
- destPath = filepath.Join(destPath, filepath.Base(srcPath))
- }
- }
if extract {
// We're extracting an archive into the destination directory.
@@ -273,9 +341,16 @@ func copy(src, destPath, dest string, idMappingOpts storage.IDMappingOptions, ch
return nil
}
- if destDirIsExist || strings.HasSuffix(dest, string(os.PathSeparator)) {
+ destfi, err := os.Stat(destPath)
+ if err != nil {
+ if !os.IsNotExist(err) {
+ return errors.Wrapf(err, "failed to get stat of dest path %s", destPath)
+ }
+ }
+ if destfi != nil && destfi.IsDir() {
destPath = filepath.Join(destPath, filepath.Base(srcPath))
}
+
// Copy the file, preserving attributes.
logrus.Debugf("copying %q to %q", srcPath, destPath)
if err = copyFileWithTar(srcPath, destPath); err != nil {
@@ -354,3 +429,69 @@ func streamFileToStdout(srcPath string, srcfi os.FileInfo) error {
}
return nil
}
+
+func isVolumeDestName(path string, ctr *libpod.Container) (bool, string, string) {
+ separator := string(os.PathSeparator)
+ if filepath.IsAbs(path) {
+ path = strings.TrimPrefix(path, separator)
+ }
+ if path == "" {
+ return false, "", ""
+ }
+ for _, vol := range ctr.Config().NamedVolumes {
+ volNamePath := strings.TrimPrefix(vol.Dest, separator)
+ if matchVolumePath(path, volNamePath) {
+ return true, vol.Dest, vol.Name
+ }
+ }
+ return false, "", ""
+}
+
+// if SRCPATH or DESTPATH is from volume mount's destination -v or --mount type=volume, generates the path with volume mount point
+func pathWithVolumeMount(ctr *libpod.Container, runtime *libpod.Runtime, volDestName, volName, path string) (string, error) {
+ destVolume, err := runtime.GetVolume(volName)
+ if err != nil {
+ return "", errors.Wrapf(err, "error getting volume destination %s", volName)
+ }
+ if !filepath.IsAbs(path) {
+ path = filepath.Join(string(os.PathSeparator), path)
+ }
+ path, err = securejoin.SecureJoin(destVolume.MountPoint(), strings.TrimPrefix(path, volDestName))
+ return path, err
+}
+
+func isBindMountDestName(path string, ctr *libpod.Container) (bool, specs.Mount) {
+ separator := string(os.PathSeparator)
+ if filepath.IsAbs(path) {
+ path = strings.TrimPrefix(path, string(os.PathSeparator))
+ }
+ if path == "" {
+ return false, specs.Mount{}
+ }
+ for _, m := range ctr.Config().Spec.Mounts {
+ if m.Type != "bind" {
+ continue
+ }
+ mDest := strings.TrimPrefix(m.Destination, separator)
+ if matchVolumePath(path, mDest) {
+ return true, m
+ }
+ }
+ return false, specs.Mount{}
+}
+
+func matchVolumePath(path, target string) bool {
+ pathStr := filepath.Clean(path)
+ target = filepath.Clean(target)
+ for len(pathStr) > len(target) && strings.Contains(pathStr, string(os.PathSeparator)) {
+ pathStr = pathStr[:strings.LastIndex(pathStr, string(os.PathSeparator))]
+ }
+ return pathStr == target
+}
+
+func pathWithBindMountSource(m specs.Mount, path string) (string, error) {
+ if !filepath.IsAbs(path) {
+ path = filepath.Join(string(os.PathSeparator), path)
+ }
+ return securejoin.SecureJoin(m.Source, strings.TrimPrefix(path, m.Destination))
+}
diff --git a/cmd/podman/create.go b/cmd/podman/create.go
index 2351f5860..3c24729c5 100644
--- a/cmd/podman/create.go
+++ b/cmd/podman/create.go
@@ -2,6 +2,7 @@ package main
import (
"fmt"
+ "strings"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/pkg/adapter"
@@ -40,7 +41,7 @@ func init() {
getCreateFlags(&createCommand.PodmanCommand)
flags := createCommand.Flags()
flags.SetInterspersed(false)
-
+ flags.SetNormalizeFunc(aliasFlags)
}
func createCmd(c *cliconfig.CreateValues) error {
@@ -57,7 +58,7 @@ func createCmd(c *cliconfig.CreateValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
cid, err := runtime.CreateContainer(getContext(), c)
if err != nil {
@@ -77,6 +78,16 @@ func createInit(c *cliconfig.PodmanCommand) error {
logrus.Warn("setting security options with --privileged has no effect")
}
+ var setNet string
+ if c.IsSet("network") {
+ setNet = c.String("network")
+ } else if c.IsSet("net") {
+ setNet = c.String("net")
+ }
+ if (c.IsSet("dns") || c.IsSet("dns-opt") || c.IsSet("dns-search")) && (setNet == "none" || strings.HasPrefix(setNet, "container:")) {
+ return errors.Errorf("conflicting options: dns and the network mode.")
+ }
+
// Docker-compatibility: the "-h" flag for run/create is reserved for
// the hostname (see https://github.com/containers/libpod/issues/1367).
diff --git a/cmd/podman/diff.go b/cmd/podman/diff.go
index 9543113d8..f052b510d 100644
--- a/cmd/podman/diff.go
+++ b/cmd/podman/diff.go
@@ -60,8 +60,9 @@ func init() {
flags.BoolVar(&diffCommand.Archive, "archive", true, "Save the diff as a tar archive")
flags.StringVar(&diffCommand.Format, "format", "", "Change the output format")
-
- flags.MarkHidden("archive")
+ flags.BoolVarP(&diffCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
+ markFlagHidden(flags, "archive")
+ markFlagHiddenForRemoteClient("latest", flags)
}
@@ -83,7 +84,7 @@ func formatJSON(output []diffOutputParams) (diffJSONOutput, error) {
}
func diffCmd(c *cliconfig.DiffValues) error {
- if len(c.InputArgs) != 1 {
+ if len(c.InputArgs) != 1 && !c.Latest {
return errors.Errorf("container, image, or layer name must be specified: podman diff [options [...]] ID-NAME")
}
@@ -91,9 +92,18 @@ func diffCmd(c *cliconfig.DiffValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
- to := c.InputArgs[0]
+ var to string
+ if c.Latest {
+ ctr, err := runtime.GetLatestContainer()
+ if err != nil {
+ return errors.Wrapf(err, "unable to get latest container")
+ }
+ to = ctr.ID()
+ } else {
+ to = c.InputArgs[0]
+ }
changes, err := runtime.Diff(c, to)
if err != nil {
return errors.Wrapf(err, "could not get changes for %q", to)
@@ -126,7 +136,5 @@ func diffCmd(c *cliconfig.DiffValues) error {
} else {
out = stdoutStruct{output: diffOutput}
}
- formats.Writer(out).Out()
-
- return nil
+ return out.Out()
}
diff --git a/cmd/podman/events.go b/cmd/podman/events.go
index 88c1010e3..18126e626 100644
--- a/cmd/podman/events.go
+++ b/cmd/podman/events.go
@@ -36,7 +36,7 @@ func init() {
flags.BoolVar(&eventsCommand.Stream, "stream", true, "stream new events; for testing only")
flags.StringVar(&eventsCommand.Since, "since", "", "show all events created since timestamp")
flags.StringVar(&eventsCommand.Until, "until", "", "show all events until timestamp")
- flags.MarkHidden("stream")
+ markFlagHidden(flags, "stream")
}
func eventsCmd(c *cliconfig.EventValues) error {
@@ -44,7 +44,7 @@ func eventsCmd(c *cliconfig.EventValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
return runtime.Events(c)
}
diff --git a/cmd/podman/exec.go b/cmd/podman/exec.go
index deff44a92..649a7b0db 100644
--- a/cmd/podman/exec.go
+++ b/cmd/podman/exec.go
@@ -1,15 +1,8 @@
package main
import (
- "fmt"
- "io/ioutil"
- "os"
- "strconv"
-
"github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/containers/libpod/cmd/podman/libpodruntime"
- "github.com/containers/libpod/cmd/podman/shared/parse"
- "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/adapter"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@@ -41,8 +34,9 @@ func init() {
execCommand.SetUsageTemplate(UsageTemplate())
flags := execCommand.Flags()
flags.SetInterspersed(false)
+ flags.StringVar(&execCommand.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.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.Interactive, "interactive", "i", false, "Keep STDIN open even if not attached")
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")
flags.BoolVarP(&execCommand.Tty, "tty", "t", false, "Allocate a pseudo-TTY. The default is false")
@@ -51,79 +45,29 @@ func init() {
flags.IntVar(&execCommand.PreserveFDs, "preserve-fds", 0, "Pass N additional file descriptors to the container")
flags.StringVarP(&execCommand.Workdir, "workdir", "w", "", "Working directory inside the container")
markFlagHiddenForRemoteClient("latest", flags)
+ markFlagHiddenForRemoteClient("preserve-fds", flags)
}
func execCmd(c *cliconfig.ExecValues) error {
- args := c.InputArgs
- var ctr *libpod.Container
- var err error
- argStart := 1
- if len(args) < 1 && !c.Latest {
- return errors.Errorf("you must provide one container name or id")
- }
- if len(args) < 2 && !c.Latest {
- return errors.Errorf("you must provide a command to exec")
- }
+ argLen := len(c.InputArgs)
if c.Latest {
- argStart = 0
- }
- cmd := args[argStart:]
- runtime, err := libpodruntime.GetRuntime(getContext(), &c.PodmanCommand)
- if err != nil {
- return errors.Wrapf(err, "error creating libpod runtime")
- }
- defer runtime.Shutdown(false)
-
- if c.Latest {
- ctr, err = runtime.GetLatestContainer()
- } else {
- ctr, err = runtime.LookupContainer(args[0])
- }
- if err != nil {
- return errors.Wrapf(err, "unable to exec into %s", args[0])
- }
-
- if c.PreserveFDs > 0 {
- entries, err := ioutil.ReadDir("/proc/self/fd")
- if err != nil {
- return errors.Wrapf(err, "unable to read /proc/self/fd")
+ if argLen < 1 {
+ return errors.Errorf("you must provide a command to exec")
}
- m := make(map[int]bool)
- for _, e := range entries {
- i, err := strconv.Atoi(e.Name())
- if err != nil {
- if err != nil {
- return errors.Wrapf(err, "cannot parse %s in /proc/self/fd", e.Name())
- }
- }
- m[i] = true
+ } else {
+ if argLen < 1 {
+ return errors.Errorf("you must provide one container name or id")
}
- for i := 3; i < 3+c.PreserveFDs; i++ {
- if _, found := m[i]; !found {
- return errors.New("invalid --preserve-fds=N specified. Not enough FDs available")
- }
+ if argLen < 2 {
+ return errors.Errorf("you must provide a command to exec")
}
-
}
-
- // ENVIRONMENT VARIABLES
- env := map[string]string{}
-
- if err := parse.ReadKVStrings(env, []string{}, c.Env); err != nil {
- return errors.Wrapf(err, "unable to process environment variables")
- }
- envs := []string{}
- for k, v := range env {
- envs = append(envs, fmt.Sprintf("%s=%s", k, v))
+ runtime, err := adapter.GetRuntimeNoStore(getContext(), &c.PodmanCommand)
+ if err != nil {
+ return errors.Wrapf(err, "error creating libpod runtime")
}
+ defer runtime.DeferredShutdown(false)
- streams := new(libpod.AttachStreams)
- streams.OutputStream = os.Stdout
- streams.ErrorStream = os.Stderr
- streams.InputStream = os.Stdin
- streams.AttachOutput = true
- streams.AttachError = true
- streams.AttachInput = true
-
- return ctr.Exec(c.Tty, c.Privileged, envs, cmd, c.User, c.Workdir, streams, c.PreserveFDs)
+ exitCode, err = runtime.ExecContainer(getContext(), c)
+ return err
}
diff --git a/cmd/podman/exists.go b/cmd/podman/exists.go
index 6619522b6..f8b1f8e59 100644
--- a/cmd/podman/exists.go
+++ b/cmd/podman/exists.go
@@ -1,14 +1,14 @@
package main
import (
- "github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/spf13/cobra"
"os"
- "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/cmd/podman/cliconfig"
+ "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/adapter"
"github.com/pkg/errors"
+ "github.com/spf13/cobra"
)
var (
@@ -90,7 +90,7 @@ func imageExistsCmd(c *cliconfig.ImageExistsValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
if _, err := runtime.NewImageFromLocal(args[0]); err != nil {
//TODO we need to ask about having varlink defined errors exposed
//so we can reuse them
@@ -107,13 +107,13 @@ func containerExistsCmd(c *cliconfig.ContainerExistsValues) error {
if len(args) > 1 || len(args) < 1 {
return errors.New("you may only check for the existence of one container at a time")
}
- runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand)
+ runtime, err := adapter.GetRuntimeNoStore(getContext(), &c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
if _, err := runtime.LookupContainer(args[0]); err != nil {
- if errors.Cause(err) == libpod.ErrNoSuchCtr || err.Error() == "io.podman.ContainerNotFound" {
+ if errors.Cause(err) == define.ErrNoSuchCtr || err.Error() == "io.podman.ContainerNotFound" {
os.Exit(1)
}
return err
@@ -126,14 +126,14 @@ func podExistsCmd(c *cliconfig.PodExistsValues) error {
if len(args) > 1 || len(args) < 1 {
return errors.New("you may only check for the existence of one pod at a time")
}
- runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand)
+ runtime, err := adapter.GetRuntimeNoStore(getContext(), &c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
if _, err := runtime.LookupPod(args[0]); err != nil {
- if errors.Cause(err) == libpod.ErrNoSuchPod || err.Error() == "io.podman.PodNotFound" {
+ if errors.Cause(err) == define.ErrNoSuchPod || err.Error() == "io.podman.PodNotFound" {
os.Exit(1)
}
return err
diff --git a/cmd/podman/export.go b/cmd/podman/export.go
index 82a4c13e7..27948004c 100644
--- a/cmd/podman/export.go
+++ b/cmd/podman/export.go
@@ -7,8 +7,8 @@ import (
"github.com/containers/libpod/cmd/podman/shared/parse"
"github.com/containers/libpod/pkg/adapter"
"github.com/pkg/errors"
- "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
+ "golang.org/x/crypto/ssh/terminal"
)
var (
@@ -45,7 +45,7 @@ func exportCmd(c *cliconfig.ExportValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
args := c.InputArgs
if len(args) == 0 {
@@ -62,7 +62,7 @@ func exportCmd(c *cliconfig.ExportValues) error {
if len(output) == 0 {
file := os.Stdout
- if logrus.IsTerminal(file) {
+ if terminal.IsTerminal(int(file.Fd())) {
return errors.Errorf("refusing to export to terminal. Use -o flag or redirect")
}
output = "/dev/stdout"
diff --git a/cmd/podman/generate_kube.go b/cmd/podman/generate_kube.go
index 318dd0771..6f04d6517 100644
--- a/cmd/podman/generate_kube.go
+++ b/cmd/podman/generate_kube.go
@@ -2,6 +2,9 @@ package main
import (
"fmt"
+ "io/ioutil"
+ "os"
+
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/pkg/adapter"
podmanVersion "github.com/containers/libpod/version"
@@ -37,6 +40,7 @@ func init() {
containerKubeCommand.SetUsageTemplate(UsageTemplate())
flags := containerKubeCommand.Flags()
flags.BoolVarP(&containerKubeCommand.Service, "service", "s", false, "Generate YAML for kubernetes service object")
+ flags.StringVarP(&containerKubeCommand.Filename, "filename", "f", "", "Filename to output to")
}
func generateKubeYAMLCmd(c *cliconfig.GenerateKubeValues) error {
@@ -58,7 +62,7 @@ func generateKubeYAMLCmd(c *cliconfig.GenerateKubeValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
podYAML, serviceYAML, err := runtime.GenerateKube(c)
if err != nil {
@@ -88,8 +92,19 @@ func generateKubeYAMLCmd(c *cliconfig.GenerateKubeValues) error {
output = append(output, []byte("---\n")...)
output = append(output, marshalledService...)
}
- // Output the v1.Pod with the v1.Container
- fmt.Println(string(output))
+
+ if c.Filename != "" {
+ if _, err := os.Stat(c.Filename); err == nil {
+ return errors.Errorf("cannot write to %q - file exists", c.Filename)
+ }
+
+ if err := ioutil.WriteFile(c.Filename, output, 0644); err != nil {
+ return err
+ }
+ } else {
+ // Output the v1.Pod with the v1.Container
+ fmt.Println(string(output))
+ }
return nil
}
diff --git a/cmd/podman/generate_systemd.go b/cmd/podman/generate_systemd.go
index b4779e512..8be097c83 100644
--- a/cmd/podman/generate_systemd.go
+++ b/cmd/podman/generate_systemd.go
@@ -50,7 +50,7 @@ func generateSystemdCmd(c *cliconfig.GenerateSystemdValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
// User input stop timeout must be 0 or greater
if c.Flag("timeout").Changed && c.StopTimeout < 0 {
diff --git a/cmd/podman/healthcheck_run.go b/cmd/podman/healthcheck_run.go
index 111318d9c..3a2a8f333 100644
--- a/cmd/podman/healthcheck_run.go
+++ b/cmd/podman/healthcheck_run.go
@@ -2,8 +2,8 @@ package main
import (
"fmt"
+
"github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/adapter"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -42,13 +42,11 @@ func healthCheckCmd(c *cliconfig.HealthCheckValues) error {
if err != nil {
return errors.Wrap(err, "could not get runtime")
}
+ defer runtime.DeferredShutdown(false)
status, err := runtime.HealthCheck(c)
- if err != nil {
- if status == libpod.HealthCheckFailure {
- fmt.Println("\nunhealthy")
- }
- return err
+ if err == nil && status == "unhealthy" {
+ exitCode = 1
}
- fmt.Println("healthy")
- return nil
+ fmt.Println(status)
+ return err
}
diff --git a/cmd/podman/history.go b/cmd/podman/history.go
index cebf99a9f..a16aac8d8 100644
--- a/cmd/podman/history.go
+++ b/cmd/podman/history.go
@@ -71,7 +71,7 @@ func historyCmd(c *cliconfig.HistoryValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
format := genHistoryFormat(c.Format, c.Quiet)
@@ -141,11 +141,12 @@ func (h *historyTemplateParams) headerMap() map[string]string {
}
// getHistorytemplateOutput gets the modified history information to be printed in human readable format
-func getHistoryTemplateOutput(history []*image.History, opts historyOptions) (historyOutput []historyTemplateParams) {
+func getHistoryTemplateOutput(history []*image.History, opts historyOptions) []historyTemplateParams {
var (
- outputSize string
- createdTime string
- createdBy string
+ outputSize string
+ createdTime string
+ createdBy string
+ historyOutput []historyTemplateParams
)
for _, hist := range history {
imageID := hist.ID
@@ -154,7 +155,7 @@ func getHistoryTemplateOutput(history []*image.History, opts historyOptions) (hi
}
if opts.human {
- createdTime = units.HumanDuration(time.Since((*hist.Created))) + " ago"
+ createdTime = units.HumanDuration(time.Since(*hist.Created)) + " ago"
outputSize = units.HumanSize(float64(hist.Size))
} else {
createdTime = (hist.Created).Format(time.RFC3339)
@@ -175,7 +176,7 @@ func getHistoryTemplateOutput(history []*image.History, opts historyOptions) (hi
}
historyOutput = append(historyOutput, params)
}
- return
+ return historyOutput
}
// generateHistoryOutput generates the history based on the format given
@@ -194,5 +195,5 @@ func generateHistoryOutput(history []*image.History, opts historyOptions) error
out = formats.StdoutTemplateArray{Output: historyToGeneric(historyOutput, []*image.History{}), Template: opts.format, Fields: historyOutput[0].headerMap()}
}
- return formats.Writer(out).Out()
+ return out.Out()
}
diff --git a/cmd/podman/imagefilters/filters.go b/cmd/podman/imagefilters/filters.go
index aa5776599..0b08314ce 100644
--- a/cmd/podman/imagefilters/filters.go
+++ b/cmd/podman/imagefilters/filters.go
@@ -46,6 +46,16 @@ func DanglingFilter(danglingImages bool) ResultFilter {
}
}
+// ReadOnlyFilter allows you to filter images based on read/only and read/write
+func ReadOnlyFilter(readOnly bool) ResultFilter {
+ return func(i *adapter.ContainerImage) bool {
+ if readOnly {
+ return i.IsReadOnly()
+ }
+ return !i.IsReadOnly()
+ }
+}
+
// LabelFilter allows you to filter by images labels key and/or value
func LabelFilter(ctx context.Context, labelfilter string) ResultFilter {
// We need to handle both label=key and label=key=value
diff --git a/cmd/podman/images.go b/cmd/podman/images.go
index 3f755efc1..fe7c89b5c 100644
--- a/cmd/podman/images.go
+++ b/cmd/podman/images.go
@@ -30,14 +30,16 @@ type imagesTemplateParams struct {
Created string
CreatedTime time.Time
Size string
+ ReadOnly bool
}
type imagesJSONParams struct {
- ID string `json:"id"`
- Name []string `json:"names"`
- Digest digest.Digest `json:"digest"`
- Created time.Time `json:"created"`
- Size *uint64 `json:"size"`
+ ID string `json:"id"`
+ Name []string `json:"names"`
+ Digest digest.Digest `json:"digest"`
+ Created time.Time `json:"created"`
+ Size *uint64 `json:"size"`
+ ReadOnly bool `json:"readonly"`
}
type imagesOptions struct {
@@ -138,7 +140,7 @@ func imagesCmd(c *cliconfig.ImagesValues) error {
if err != nil {
return errors.Wrapf(err, "Could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
if len(c.InputArgs) == 1 {
image = c.InputArgs[0]
}
@@ -175,6 +177,13 @@ func imagesCmd(c *cliconfig.ImagesValues) error {
return errors.Wrapf(err, "unable to get images")
}
+ for _, image := range images {
+ if image.IsReadOnly() {
+ opts.outputformat += "{{.ReadOnly}}\t"
+ break
+ }
+ }
+
var filteredImages []*adapter.ContainerImage
//filter the images
if len(c.Filter) > 0 || len(c.InputArgs) == 1 {
@@ -238,7 +247,8 @@ func sortImagesOutput(sortBy string, imagesOutput imagesSorted) imagesSorted {
}
// getImagesTemplateOutput returns the images information to be printed in human readable format
-func getImagesTemplateOutput(ctx context.Context, images []*adapter.ContainerImage, opts imagesOptions) (imagesOutput imagesSorted) {
+func getImagesTemplateOutput(ctx context.Context, images []*adapter.ContainerImage, opts imagesOptions) imagesSorted {
+ var imagesOutput imagesSorted
for _, img := range images {
// If all is false and the image doesn't have a name, check to see if the top layer of the image is a parent
// to another image's top layer. If it is, then it is an intermediate image so don't print out if the --all flag
@@ -280,8 +290,9 @@ func getImagesTemplateOutput(ctx context.Context, images []*adapter.ContainerIma
ID: imageID,
Digest: img.Digest(),
CreatedTime: createdTime,
- Created: units.HumanDuration(time.Since((createdTime))) + " ago",
+ Created: units.HumanDuration(time.Since(createdTime)) + " ago",
Size: sizeStr,
+ ReadOnly: img.IsReadOnly(),
}
imagesOutput = append(imagesOutput, params)
if opts.quiet { // Show only one image ID when quiet
@@ -294,7 +305,7 @@ func getImagesTemplateOutput(ctx context.Context, images []*adapter.ContainerIma
// Sort images by created time
sortImagesOutput(opts.sort, imagesOutput)
- return
+ return imagesOutput
}
// getImagesJSONOutput returns the images information in its raw form
@@ -305,11 +316,12 @@ func getImagesJSONOutput(ctx context.Context, images []*adapter.ContainerImage)
size = nil
}
params := imagesJSONParams{
- ID: img.ID(),
- Name: img.Names(),
- Digest: img.Digest(),
- Created: img.Created(),
- Size: size,
+ ID: img.ID(),
+ Name: img.Names(),
+ Digest: img.Digest(),
+ Created: img.Created(),
+ Size: size,
+ ReadOnly: img.IsReadOnly(),
}
imagesOutput = append(imagesOutput, params)
}
@@ -334,7 +346,7 @@ func generateImagesOutput(ctx context.Context, images []*adapter.ContainerImage,
imagesOutput := getImagesTemplateOutput(ctx, images, opts)
out = formats.StdoutTemplateArray{Output: imagesToGeneric(imagesOutput, []imagesJSONParams{}), Template: opts.outputformat, Fields: templateMap}
}
- return formats.Writer(out).Out()
+ return out.Out()
}
// GenImageOutputMap generates the map used for outputting the images header
@@ -351,6 +363,11 @@ func GenImageOutputMap() map[string]string {
if value == "ID" {
value = "Image" + value
}
+
+ if value == "ReadOnly" {
+ values[key] = "R/O"
+ continue
+ }
values[key] = strings.ToUpper(splitCamelCase(value))
}
return values
@@ -378,6 +395,12 @@ func CreateFilterFuncs(ctx context.Context, r *adapter.LocalRuntime, filters []s
return nil, errors.Wrapf(err, "unable to find image %s in local stores", splitFilter[1])
}
filterFuncs = append(filterFuncs, imagefilters.CreatedAfterFilter(after.Created()))
+ case "readonly":
+ readonly, err := strconv.ParseBool(splitFilter[1])
+ if err != nil {
+ return nil, errors.Wrapf(err, "invalid filter readonly=%s", splitFilter[1])
+ }
+ filterFuncs = append(filterFuncs, imagefilters.ReadOnlyFilter(readonly))
case "dangling":
danglingImages, err := strconv.ParseBool(splitFilter[1])
if err != nil {
diff --git a/cmd/podman/images_prune.go b/cmd/podman/images_prune.go
index 1ac5bc65d..5745edd6b 100644
--- a/cmd/podman/images_prune.go
+++ b/cmd/podman/images_prune.go
@@ -41,7 +41,7 @@ func pruneImagesCmd(c *cliconfig.PruneImagesValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
// Call prune; if any cids are returned, print them and then
// return err in case an error also came up
diff --git a/cmd/podman/import.go b/cmd/podman/import.go
index 167d9f2c9..d49792f27 100644
--- a/cmd/podman/import.go
+++ b/cmd/podman/import.go
@@ -6,6 +6,7 @@ import (
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/shared/parse"
"github.com/containers/libpod/pkg/adapter"
+ multierror "github.com/hashicorp/go-multierror"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@@ -49,7 +50,7 @@ func importCmd(c *cliconfig.ImportValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
var (
source string
@@ -69,8 +70,11 @@ func importCmd(c *cliconfig.ImportValues) error {
return errors.Errorf("too many arguments. Usage TARBALL [REFERENCE]")
}
- if err := parse.ValidateFileName(source); err != nil {
- return err
+ errFileName := parse.ValidateFileName(source)
+ errURL := parse.ValidURL(source)
+
+ if errFileName != nil && errURL != nil {
+ return multierror.Append(errFileName, errURL)
}
quiet := c.Quiet
diff --git a/cmd/podman/info.go b/cmd/podman/info.go
index 823303354..bf6dd4a8f 100644
--- a/cmd/podman/info.go
+++ b/cmd/podman/info.go
@@ -6,7 +6,7 @@ import (
"github.com/containers/buildah/pkg/formats"
"github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/adapter"
"github.com/containers/libpod/version"
"github.com/pkg/errors"
@@ -55,7 +55,7 @@ func infoCmd(c *cliconfig.InfoValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
infoArr, err := runtime.Info()
if err != nil {
@@ -74,12 +74,12 @@ func infoCmd(c *cliconfig.InfoValues) error {
remoteClientInfo["RemoteAPI Version"] = version.RemoteAPIVersion
remoteClientInfo["Podman Version"] = version.Version
remoteClientInfo["OS Arch"] = fmt.Sprintf("%s/%s", rt.GOOS, rt.GOARCH)
- infoArr = append(infoArr, libpod.InfoData{Type: "client", Data: remoteClientInfo})
+ infoArr = append(infoArr, define.InfoData{Type: "client", Data: remoteClientInfo})
}
if !runtime.Remote && c.Debug {
debugInfo := debugInfo(c)
- infoArr = append(infoArr, libpod.InfoData{Type: "debug", Data: debugInfo})
+ infoArr = append(infoArr, define.InfoData{Type: "debug", Data: debugInfo})
}
for _, currInfo := range infoArr {
@@ -97,9 +97,7 @@ func infoCmd(c *cliconfig.InfoValues) error {
out = formats.StdoutTemplate{Output: info, Template: infoOutputFormat}
}
- formats.Writer(out).Out()
-
- return nil
+ return out.Out()
}
// top-level "debug" info
@@ -108,7 +106,7 @@ func debugInfo(c *cliconfig.InfoValues) map[string]interface{} {
info["compiler"] = rt.Compiler
info["go version"] = rt.Version()
info["podman version"] = version.Version
- version, _ := libpod.GetVersion()
+ version, _ := define.GetVersion()
info["git commit"] = version.GitCommit
return info
}
diff --git a/cmd/podman/init.go b/cmd/podman/init.go
index 68c80631d..3f97824fc 100644
--- a/cmd/podman/init.go
+++ b/cmd/podman/init.go
@@ -54,7 +54,7 @@ func initCmd(c *cliconfig.InitValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
ok, failures, err := runtime.InitContainers(ctx, c)
if err != nil {
diff --git a/cmd/podman/inspect.go b/cmd/podman/inspect.go
index 4303c149c..cff221cb0 100644
--- a/cmd/podman/inspect.go
+++ b/cmd/podman/inspect.go
@@ -6,9 +6,7 @@ import (
"github.com/containers/buildah/pkg/formats"
"github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/pkg/adapter"
- cc "github.com/containers/libpod/pkg/spec"
"github.com/containers/libpod/pkg/util"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -88,7 +86,7 @@ func inspectCmd(c *cliconfig.InspectValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
if !util.StringInSlice(inspectType, []string{inspectTypeContainer, inspectTypeImage, inspectAll}) {
return errors.Errorf("the only recognized types are %q, %q, and %q", inspectTypeContainer, inspectTypeImage, inspectAll)
@@ -98,6 +96,14 @@ func inspectCmd(c *cliconfig.InspectValues) error {
if strings.Contains(outputFormat, "{{.Id}}") {
outputFormat = strings.Replace(outputFormat, "{{.Id}}", formats.IDString, -1)
}
+ // These fields were renamed, so we need to provide backward compat for
+ // the old names.
+ if strings.Contains(outputFormat, ".Src") {
+ outputFormat = strings.Replace(outputFormat, ".Src", ".Source", -1)
+ }
+ if strings.Contains(outputFormat, ".Dst") {
+ outputFormat = strings.Replace(outputFormat, ".Dst", ".Destination", -1)
+ }
if latestContainer {
lc, err := runtime.GetLatestContainer()
if err != nil {
@@ -121,7 +127,7 @@ func inspectCmd(c *cliconfig.InspectValues) error {
out = formats.JSONStructArray{Output: inspectedObjects}
}
- return formats.Writer(out).Out()
+ return out.Out()
}
// func iterateInput iterates the images|containers the user has requested and returns the inspect data and error
@@ -140,19 +146,9 @@ func iterateInput(ctx context.Context, size bool, args []string, runtime *adapte
inspectError = errors.Wrapf(err, "error looking up container %q", input)
break
}
- libpodInspectData, err := ctr.Inspect(size)
+ data, err = ctr.Inspect(size)
if err != nil {
- inspectError = errors.Wrapf(err, "error getting libpod container inspect data %s", ctr.ID())
- break
- }
- artifact, err := getArtifact(ctr)
- if inspectError != nil {
- inspectError = err
- break
- }
- data, err = shared.GetCtrInspectInfo(ctr.Config(), libpodInspectData, artifact)
- if err != nil {
- inspectError = errors.Wrapf(err, "error parsing container data %q", ctr.ID())
+ inspectError = errors.Wrapf(err, "error inspecting container %s", ctr.ID())
break
}
case inspectTypeImage:
@@ -180,19 +176,9 @@ func iterateInput(ctx context.Context, size bool, args []string, runtime *adapte
break
}
} else {
- libpodInspectData, err := ctr.Inspect(size)
+ data, err = ctr.Inspect(size)
if err != nil {
- inspectError = errors.Wrapf(err, "error getting libpod container inspect data %s", ctr.ID())
- break
- }
- artifact, inspectError := getArtifact(ctr)
- if inspectError != nil {
- inspectError = err
- break
- }
- data, err = shared.GetCtrInspectInfo(ctr.Config(), libpodInspectData, artifact)
- if err != nil {
- inspectError = errors.Wrapf(err, "error parsing container data %s", ctr.ID())
+ inspectError = errors.Wrapf(err, "error inspecting container %s", ctr.ID())
break
}
}
@@ -203,15 +189,3 @@ func iterateInput(ctx context.Context, size bool, args []string, runtime *adapte
}
return inspectedItems, inspectError
}
-
-func getArtifact(ctr *adapter.Container) (*cc.CreateConfig, error) {
- var createArtifact cc.CreateConfig
- artifact, err := ctr.GetArtifact("create-config")
- if err != nil {
- return nil, err
- }
- if err := json.Unmarshal(artifact, &createArtifact); err != nil {
- return nil, err
- }
- return &createArtifact, nil
-}
diff --git a/cmd/podman/kill.go b/cmd/podman/kill.go
index edf69ff2e..d5056d86d 100644
--- a/cmd/podman/kill.go
+++ b/cmd/podman/kill.go
@@ -63,7 +63,7 @@ func killCmd(c *cliconfig.KillValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
ok, failures, err := runtime.KillContainers(getContext(), c, killSignal)
if err != nil {
diff --git a/cmd/podman/libpodruntime/runtime.go b/cmd/podman/libpodruntime/runtime.go
index 898c81515..570288837 100644
--- a/cmd/podman/libpodruntime/runtime.go
+++ b/cmd/podman/libpodruntime/runtime.go
@@ -5,6 +5,7 @@ import (
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/cgroups"
"github.com/containers/libpod/pkg/namespaces"
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/pkg/util"
@@ -14,20 +15,25 @@ import (
// GetRuntimeMigrate gets a libpod runtime that will perform a migration of existing containers
func GetRuntimeMigrate(ctx context.Context, c *cliconfig.PodmanCommand) (*libpod.Runtime, error) {
- return getRuntime(ctx, c, false, true)
+ return getRuntime(ctx, c, false, true, false)
}
// GetRuntimeRenumber gets a libpod runtime that will perform a lock renumber
func GetRuntimeRenumber(ctx context.Context, c *cliconfig.PodmanCommand) (*libpod.Runtime, error) {
- return getRuntime(ctx, c, true, false)
+ return getRuntime(ctx, c, true, false, false)
}
// GetRuntime generates a new libpod runtime configured by command line options
func GetRuntime(ctx context.Context, c *cliconfig.PodmanCommand) (*libpod.Runtime, error) {
- return getRuntime(ctx, c, false, false)
+ return getRuntime(ctx, c, false, false, false)
}
-func getRuntime(ctx context.Context, c *cliconfig.PodmanCommand, renumber bool, migrate bool) (*libpod.Runtime, error) {
+// GetRuntimeNoStore generates a new libpod runtime configured by command line options
+func GetRuntimeNoStore(ctx context.Context, c *cliconfig.PodmanCommand) (*libpod.Runtime, error) {
+ return getRuntime(ctx, c, false, false, true)
+}
+
+func getRuntime(ctx context.Context, c *cliconfig.PodmanCommand, renumber, migrate, noStore bool) (*libpod.Runtime, error) {
options := []libpod.RuntimeOption{}
storageOpts := storage.StoreOptions{}
storageSet := false
@@ -67,7 +73,10 @@ func getRuntime(ctx context.Context, c *cliconfig.PodmanCommand, renumber bool,
if c.Flags().Changed("storage-driver") {
storageSet = true
storageOpts.GraphDriverName = c.GlobalFlags.StorageDriver
+ // Overriding the default storage driver caused GraphDriverOptions from storage.conf to be ignored
+ storageOpts.GraphDriverOptions = []string{}
}
+ // This should always be checked after storage-driver is checked
if len(c.GlobalFlags.StorageOpts) > 0 {
storageSet = true
storageOpts.GraphDriverOptions = c.GlobalFlags.StorageOpts
@@ -85,6 +94,9 @@ func getRuntime(ctx context.Context, c *cliconfig.PodmanCommand, renumber bool,
options = append(options, libpod.WithStorageConfig(storageOpts))
}
+ if !storageSet && noStore {
+ options = append(options, libpod.WithNoStore())
+ }
// TODO CLI flags for image config?
// TODO CLI flag for signature policy?
@@ -109,7 +121,7 @@ func getRuntime(ctx context.Context, c *cliconfig.PodmanCommand, renumber bool,
if c.Flags().Changed("cgroup-manager") {
options = append(options, libpod.WithCgroupManager(c.GlobalFlags.CGroupManager))
} else {
- unified, err := util.IsCgroup2UnifiedMode()
+ unified, err := cgroups.IsCgroup2UnifiedMode()
if err != nil {
return nil, err
}
diff --git a/cmd/podman/load.go b/cmd/podman/load.go
index 0c41eb792..ed6a4e5fa 100644
--- a/cmd/podman/load.go
+++ b/cmd/podman/load.go
@@ -43,7 +43,7 @@ func init() {
// Disabled flags for the remote client
if !remote {
flags.StringVar(&loadCommand.SignaturePolicy, "signature-policy", "", "Pathname of signature policy file (not usually used)")
- flags.MarkHidden("signature-policy")
+ markFlagHidden(flags, "signature-policy")
}
}
@@ -65,7 +65,7 @@ func loadCmd(c *cliconfig.LoadValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
if len(c.Input) > 0 {
if err := parse.ValidateFileName(c.Input); err != nil {
diff --git a/cmd/podman/login.go b/cmd/podman/login.go
index 3a78adadc..36262fd4d 100644
--- a/cmd/podman/login.go
+++ b/cmd/podman/login.go
@@ -10,6 +10,7 @@ import (
"github.com/containers/image/pkg/docker/config"
"github.com/containers/image/types"
"github.com/containers/libpod/cmd/podman/cliconfig"
+ "github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod/image"
"github.com/docker/docker-credential-helpers/credentials"
"github.com/pkg/errors"
@@ -52,7 +53,7 @@ func init() {
flags.BoolVar(&loginCommand.StdinPassword, "password-stdin", false, "Take the password from stdin")
// Disabled flags for the remote client
if !remote {
- flags.StringVar(&loginCommand.Authfile, "authfile", getAuthFile(""), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
+ flags.StringVar(&loginCommand.Authfile, "authfile", shared.GetAuthFile(""), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
flags.StringVar(&loginCommand.CertDir, "cert-dir", "", "Pathname of a directory containing TLS certificates and keys used to connect to the registry")
flags.BoolVar(&loginCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries")
}
diff --git a/cmd/podman/logout.go b/cmd/podman/logout.go
index 5df838bba..66dc82363 100644
--- a/cmd/podman/logout.go
+++ b/cmd/podman/logout.go
@@ -6,6 +6,7 @@ import (
"github.com/containers/image/docker"
"github.com/containers/image/pkg/docker/config"
"github.com/containers/libpod/cmd/podman/cliconfig"
+ "github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod/image"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -39,7 +40,7 @@ func init() {
logoutCommand.SetUsageTemplate(UsageTemplate())
flags := logoutCommand.Flags()
flags.BoolVarP(&logoutCommand.All, "all", "a", false, "Remove the cached credentials for all registries in the auth file")
- flags.StringVar(&logoutCommand.Authfile, "authfile", getAuthFile(""), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
+ flags.StringVar(&logoutCommand.Authfile, "authfile", shared.GetAuthFile(""), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
markFlagHiddenForRemoteClient("authfile", flags)
}
diff --git a/cmd/podman/logs.go b/cmd/podman/logs.go
index a1ec9f4ee..32605389e 100644
--- a/cmd/podman/logs.go
+++ b/cmd/podman/logs.go
@@ -4,7 +4,7 @@ import (
"time"
"github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/logs"
"github.com/containers/libpod/pkg/adapter"
"github.com/containers/libpod/pkg/util"
"github.com/pkg/errors"
@@ -54,8 +54,7 @@ func init() {
flags.StringVar(&logsCommand.Since, "since", "", "Show logs since TIMESTAMP")
flags.Uint64Var(&logsCommand.Tail, "tail", 0, "Output the specified number of LINES at the end of the logs. Defaults to 0, which prints all lines")
flags.BoolVarP(&logsCommand.Timestamps, "timestamps", "t", false, "Output the timestamps in the log")
- flags.MarkHidden("details")
-
+ markFlagHidden(flags, "details")
flags.SetInterspersed(false)
markFlagHiddenForRemoteClient("latest", flags)
@@ -68,7 +67,7 @@ func logsCmd(c *cliconfig.LogsValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
sinceTime := time.Time{}
if c.Flag("since").Changed {
@@ -80,13 +79,12 @@ func logsCmd(c *cliconfig.LogsValues) error {
sinceTime = since
}
- opts := &libpod.LogOptions{
+ options := &logs.LogOptions{
Details: c.Details,
Follow: c.Follow,
Since: sinceTime,
Tail: c.Tail,
Timestamps: c.Timestamps,
}
-
- return runtime.Log(c, opts)
+ return runtime.Log(c, options)
}
diff --git a/cmd/podman/main.go b/cmd/podman/main.go
index 787dd55c0..72d1754ac 100644
--- a/cmd/podman/main.go
+++ b/cmd/podman/main.go
@@ -4,6 +4,7 @@ import (
"context"
"io"
"os"
+ "path"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/libpod"
@@ -30,9 +31,11 @@ var (
var mainCommands = []*cobra.Command{
_attachCommand,
_buildCommand,
+ _commitCommand,
_diffCommand,
_createCommand,
_eventsCommand,
+ _execCommand,
_exportCommand,
_generateCommand,
_historyCommand,
@@ -58,7 +61,6 @@ var mainCommands = []*cobra.Command{
_stopCommand,
_tagCommand,
_topCommand,
- _umountCommand,
_unpauseCommand,
_versionCommand,
_waitCommand,
@@ -68,7 +70,7 @@ var mainCommands = []*cobra.Command{
}
var rootCmd = &cobra.Command{
- Use: "podman",
+ Use: path.Base(os.Args[0]),
Long: "manage pods and images",
RunE: commandRunE(),
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
@@ -99,10 +101,11 @@ func initConfig() {
}
func before(cmd *cobra.Command, args []string) error {
- if err := libpod.SetXdgRuntimeDir(""); err != nil {
+ if err := libpod.SetXdgRuntimeDir(); err != nil {
logrus.Errorf(err.Error())
os.Exit(1)
}
+
if err := setupRootless(cmd, args); err != nil {
return err
}
@@ -117,6 +120,9 @@ func before(cmd *cobra.Command, args []string) error {
return err
}
logrus.SetLevel(level)
+ if err := setSyslog(); err != nil {
+ return err
+ }
if err := setRLimits(); err != nil {
return err
diff --git a/cmd/podman/main_local.go b/cmd/podman/main_local.go
index b4f21bd0c..e4f521bc4 100644
--- a/cmd/podman/main_local.go
+++ b/cmd/podman/main_local.go
@@ -12,6 +12,8 @@ import (
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/libpodruntime"
+ "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/cgroups"
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/pkg/tracing"
"github.com/containers/libpod/pkg/util"
@@ -25,8 +27,17 @@ import (
const remote = false
func init() {
-
- rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.CGroupManager, "cgroup-manager", "", "Cgroup manager to use (cgroupfs or systemd, default systemd)")
+ cgroupManager := libpod.SystemdCgroupsManager
+ if runtimeConfig, err := libpod.DefaultRuntimeConfig(); err == nil {
+ cgroupManager = runtimeConfig.CgroupManager
+ }
+ cgroupHelp := "Cgroup manager to use (cgroupfs or systemd)"
+ cgroupv2, _ := cgroups.IsCgroup2UnifiedMode()
+ if rootless.IsRootless() && !cgroupv2 {
+ cgroupManager = ""
+ cgroupHelp = "Cgroup manager is not supported in rootless mode"
+ }
+ rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.CGroupManager, "cgroup-manager", cgroupManager, cgroupHelp)
// -c is deprecated due to conflict with -c on subcommands
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.CpuProfile, "cpu-profile", "", "Path for the cpu profiling results")
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.Config, "config", "", "Path of a libpod config file detailing container server configuration options")
@@ -34,21 +45,25 @@ func init() {
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.NetworkCmdPath, "network-cmd-path", "", "Path to the command for configuring the network")
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.CniConfigDir, "cni-config-dir", "", "Path of the configuration directory for CNI networks")
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.DefaultMountsFile, "default-mounts-file", "", "Path to default mounts file")
- rootCmd.PersistentFlags().MarkHidden("defaults-mount-file")
+ if err := rootCmd.PersistentFlags().MarkHidden("default-mounts-file"); err != nil {
+ logrus.Error("unable to mark default-mounts-file flag as hidden")
+ }
// Override default --help information of `--help` global flag
var dummyHelp bool
rootCmd.PersistentFlags().BoolVar(&dummyHelp, "help", false, "Help for podman")
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, fatal or panic")
rootCmd.PersistentFlags().IntVar(&MainGlobalOpts.MaxWorks, "max-workers", 0, "The maximum number of workers for parallel operations")
- rootCmd.PersistentFlags().MarkHidden("max-workers")
+ if err := rootCmd.PersistentFlags().MarkHidden("max-workers"); err != nil {
+ logrus.Error("unable to mark max-workers flag as hidden")
+ }
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.Namespace, "namespace", "", "Set the libpod namespace, used to create separate views of the containers and pods on the system")
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.Root, "root", "", "Path to the root directory in which data, including images, is stored")
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.Runroot, "runroot", "", "Path to the 'run directory' where all state information is stored")
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.Runtime, "runtime", "", "Path to the OCI-compatible binary used to run containers, default is /usr/bin/runc")
// -s is depracated due to conflict with -s on subcommands
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.StorageDriver, "storage-driver", "", "Select which storage driver is used to manage storage of images and containers (default is overlay)")
- rootCmd.PersistentFlags().StringSliceVar(&MainGlobalOpts.StorageOpts, "storage-opt", []string{}, "Used to pass an option to the storage driver")
+ rootCmd.PersistentFlags().StringArrayVar(&MainGlobalOpts.StorageOpts, "storage-opt", []string{}, "Used to pass an option to the storage driver")
rootCmd.PersistentFlags().BoolVar(&MainGlobalOpts.Syslog, "syslog", false, "Output logging information to syslog as well as the console")
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.TmpDir, "tmpdir", "", "Path to the tmp directory")
@@ -107,10 +122,10 @@ func setupRootless(cmd *cobra.Command, args []string) error {
return nil
}
podmanCmd := cliconfig.PodmanCommand{
- cmd,
- args,
- MainGlobalOpts,
- remoteclient,
+ Command: cmd,
+ InputArgs: args,
+ GlobalFlags: MainGlobalOpts,
+ Remote: remoteclient,
}
pausePidPath, err := util.GetRootlessPauseProcessPidPath()
@@ -137,7 +152,7 @@ func setupRootless(cmd *cobra.Command, args []string) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
ctrs, err := runtime.GetRunningContainers()
if err != nil {
diff --git a/cmd/podman/main_remote.go b/cmd/podman/main_remote.go
index c8bb3ad3e..ecbb44d5a 100644
--- a/cmd/podman/main_remote.go
+++ b/cmd/podman/main_remote.go
@@ -3,20 +3,63 @@
package main
import (
+ "fmt"
+ "os"
+ "os/user"
+ "path/filepath"
+
+ "github.com/docker/docker/pkg/homedir"
+ "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
const remote = true
func init() {
- rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.RemoteUserName, "username", "", "username on the remote host")
+ var username string
+ if curruser, err := user.Current(); err == nil {
+ username = curruser.Username
+ }
+ rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.ConnectionName, "connection", "", "remote connection name")
+ rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.RemoteConfigFilePath, "remote-config-path", "", "alternate path for configuration file")
+ rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.RemoteUserName, "username", username, "username on the remote host")
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.RemoteHost, "remote-host", "", "remote host")
// TODO maybe we allow the altering of this for bridge connections?
- //rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.VarlinkAddress, "varlink-address", adapter.DefaultAddress, "address of the varlink socket")
- rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.LogLevel, "log-level", "error", "Log messages above specified level: debug, info, warn, error, fatal or panic")
+ // rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.VarlinkAddress, "varlink-address", adapter.DefaultAddress, "address of the varlink socket")
+ rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.LogLevel, "log-level", "error", "Log messages above specified level: debug, info, warn, error, fatal or panic. Logged to ~/.config/containers/podman.log")
+ rootCmd.PersistentFlags().BoolVar(&MainGlobalOpts.Syslog, "syslog", false, "Output logging information to syslog as well as the console")
}
func setSyslog() error {
+ // Log to file if not using syslog
+ homeDir := homedir.Get()
+ path := filepath.Join(homeDir, ".config", "containers")
+
+ if _, err := os.Stat(path); os.IsNotExist(err) {
+ if err := os.MkdirAll(path, 0750); err != nil {
+ fmt.Fprintf(os.Stderr, "%v", err)
+ return err
+ }
+ }
+
+ // Update path to include file name
+ path = filepath.Join(path, "podman.log")
+
+ // Create the log file if doesn't exist. And append to it if it already exists.
+ file, err := os.OpenFile(path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0640)
+ if err != nil {
+ // Cannot open log file. Logging to stderr
+ fmt.Fprintf(os.Stderr, "%v", err)
+ return err
+ } else {
+ formatter := new(logrus.TextFormatter)
+ formatter.FullTimestamp = true
+ logrus.SetFormatter(formatter)
+ logrus.SetOutput(file)
+ }
+
+ // Note this message is only logged if --log-level >= Info!
+ logrus.Infof("Logging level set to %s", logrus.GetLevel().String())
return nil
}
diff --git a/cmd/podman/mount.go b/cmd/podman/mount.go
index 662fb0a28..b14827592 100644
--- a/cmd/podman/mount.go
+++ b/cmd/podman/mount.go
@@ -65,7 +65,7 @@ func mountCmd(c *cliconfig.MountValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
if os.Geteuid() != 0 {
rtc, err := runtime.GetConfig()
diff --git a/cmd/podman/pause.go b/cmd/podman/pause.go
index cd8370082..3a8f4edb5 100644
--- a/cmd/podman/pause.go
+++ b/cmd/podman/pause.go
@@ -1,11 +1,10 @@
package main
import (
- "os"
-
"github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/adapter"
+ "github.com/containers/libpod/pkg/rootless"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@@ -39,7 +38,7 @@ func init() {
}
func pauseCmd(c *cliconfig.PauseValues) error {
- if os.Geteuid() != 0 {
+ if rootless.IsRootless() && !remoteclient {
return errors.New("pause is not supported for rootless containers")
}
@@ -47,7 +46,7 @@ func pauseCmd(c *cliconfig.PauseValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
args := c.InputArgs
if len(args) < 1 && !c.All {
@@ -55,7 +54,7 @@ func pauseCmd(c *cliconfig.PauseValues) error {
}
ok, failures, err := runtime.PauseContainers(getContext(), c)
if err != nil {
- if errors.Cause(err) == libpod.ErrNoSuchCtr {
+ if errors.Cause(err) == define.ErrNoSuchCtr {
if len(c.InputArgs) > 1 {
exitCode = 125
} else {
diff --git a/cmd/podman/platform_linux.go b/cmd/podman/platform_linux.go
index 2127923ae..eb11867cc 100644
--- a/cmd/podman/platform_linux.go
+++ b/cmd/podman/platform_linux.go
@@ -4,13 +4,25 @@ package main
import (
"os"
+ "path/filepath"
+ "github.com/containers/libpod/pkg/rootless"
"github.com/sirupsen/logrus"
)
+// userRegistriesFile is the path to the per user registry configuration file.
+var userRegistriesFile = filepath.Join(os.Getenv("HOME"), ".config/containers/registries.conf")
+
func CheckForRegistries() {
if _, err := os.Stat("/etc/containers/registries.conf"); err != nil {
if os.IsNotExist(err) {
+ // If it is running in rootless mode, also check the user configuration file
+ if rootless.IsRootless() {
+ if _, err := os.Stat(userRegistriesFile); err != nil {
+ logrus.Warnf("unable to find %s. some podman (image shortnames) commands may be limited", userRegistriesFile)
+ }
+ return
+ }
logrus.Warn("unable to find /etc/containers/registries.conf. some podman (image shortnames) commands may be limited")
}
}
diff --git a/cmd/podman/play_kube.go b/cmd/podman/play_kube.go
index b0f4a44eb..9a5cc3ec1 100644
--- a/cmd/podman/play_kube.go
+++ b/cmd/podman/play_kube.go
@@ -1,35 +1,12 @@
package main
import (
- "context"
"fmt"
- "io"
- "io/ioutil"
- "os"
- "strings"
-
- "github.com/containers/image/types"
"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"
- ns "github.com/containers/libpod/pkg/namespaces"
- "github.com/containers/libpod/pkg/spec"
- "github.com/containers/storage"
- "github.com/cri-o/ocicni/pkg/ocicni"
- "github.com/ghodss/yaml"
+ "github.com/containers/libpod/pkg/adapter"
"github.com/pkg/errors"
- "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
- "k8s.io/api/core/v1"
-)
-
-const (
- // https://kubernetes.io/docs/concepts/storage/volumes/#hostpath
- createDirectoryPermission = 0755
- // https://kubernetes.io/docs/concepts/storage/volumes/#hostpath
- createFilePermission = 0644
)
var (
@@ -63,11 +40,11 @@ func init() {
flags.BoolVarP(&playKubeCommand.Quiet, "quiet", "q", false, "Suppress output information when pulling images")
// Disabled flags for the remote client
if !remote {
- flags.StringVar(&playKubeCommand.Authfile, "authfile", getAuthFile(""), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
+ flags.StringVar(&playKubeCommand.Authfile, "authfile", shared.GetAuthFile(""), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
flags.StringVar(&playKubeCommand.CertDir, "cert-dir", "", "`Pathname` of a directory containing TLS certificates and keys")
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")
- flags.MarkHidden("signature-policy")
+ markFlagHidden(flags, "signature-policy")
}
}
@@ -81,289 +58,12 @@ func playKubeCmd(c *cliconfig.KubePlayValues) error {
}
ctx := getContext()
- runtime, err := libpodruntime.GetRuntime(ctx, &c.PodmanCommand)
+ runtime, err := adapter.GetRuntime(ctx, &c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
- pod, err := playKubeYAMLCmd(c, ctx, runtime, args[0])
- if err != nil && pod != nil {
- if err2 := runtime.RemovePod(ctx, pod, true, true); err2 != nil {
- logrus.Errorf("unable to remove pod %s after failing to play kube", pod.ID())
- }
- }
+ _, err = runtime.PlayKubeYAML(ctx, c, args[0])
return err
}
-
-func playKubeYAMLCmd(c *cliconfig.KubePlayValues, ctx context.Context, runtime *libpod.Runtime, yamlFile string) (*libpod.Pod, error) {
- var (
- containers []*libpod.Container
- pod *libpod.Pod
- podOptions []libpod.PodCreateOption
- podYAML v1.Pod
- registryCreds *types.DockerAuthConfig
- writer io.Writer
- )
-
- content, err := ioutil.ReadFile(yamlFile)
- if err != nil {
- return nil, err
- }
-
- if err := yaml.Unmarshal(content, &podYAML); err != nil {
- return nil, errors.Wrapf(err, "unable to read %s as YAML", yamlFile)
- }
-
- // check for name collision between pod and container
- podName := podYAML.ObjectMeta.Name
- for _, n := range podYAML.Spec.Containers {
- if n.Name == podName {
- fmt.Printf("a container exists with the same name (%s) as the pod in your YAML file; changing pod name to %s_pod\n", podName, podName)
- podName = fmt.Sprintf("%s_pod", podName)
- }
- }
-
- podOptions = append(podOptions, libpod.WithInfraContainer())
- podOptions = append(podOptions, libpod.WithPodName(podName))
- // TODO for now we just used the default kernel namespaces; we need to add/subtract this from yaml
-
- nsOptions, err := shared.GetNamespaceOptions(strings.Split(shared.DefaultKernelNamespaces, ","))
- if err != nil {
- return nil, err
- }
- podOptions = append(podOptions, nsOptions...)
- podPorts := getPodPorts(podYAML.Spec.Containers)
- podOptions = append(podOptions, libpod.WithInfraContainerPorts(podPorts))
-
- // Create the Pod
- pod, err = runtime.NewPod(ctx, podOptions...)
- if err != nil {
- return pod, err
- }
-
- podInfraID, err := pod.InfraContainerID()
- if err != nil {
- return pod, err
- }
-
- namespaces := map[string]string{
- // Disabled during code review per mheon
- //"pid": fmt.Sprintf("container:%s", podInfraID),
- "net": fmt.Sprintf("container:%s", podInfraID),
- "user": fmt.Sprintf("container:%s", podInfraID),
- "ipc": fmt.Sprintf("container:%s", podInfraID),
- "uts": fmt.Sprintf("container:%s", podInfraID),
- }
- if !c.Quiet {
- writer = os.Stderr
- }
-
- dockerRegistryOptions := image.DockerRegistryOptions{
- DockerRegistryCreds: registryCreds,
- DockerCertPath: c.CertDir,
- }
- if c.Flag("tls-verify").Changed {
- dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!c.TlsVerify)
- }
-
- // map from name to mount point
- volumes := make(map[string]string)
- for _, volume := range podYAML.Spec.Volumes {
- hostPath := volume.VolumeSource.HostPath
- if hostPath == nil {
- return pod, errors.Errorf("HostPath is currently the only supported VolumeSource")
- }
- if hostPath.Type != nil {
- switch *hostPath.Type {
- case v1.HostPathDirectoryOrCreate:
- if _, err := os.Stat(hostPath.Path); os.IsNotExist(err) {
- if err := os.Mkdir(hostPath.Path, createDirectoryPermission); err != nil {
- return pod, errors.Errorf("Error creating HostPath %s at %s", volume.Name, hostPath.Path)
- }
- }
- // unconditionally label a newly created volume as private
- if err := libpod.LabelVolumePath(hostPath.Path, false); err != nil {
- return pod, errors.Wrapf(err, "Error giving %s a label", hostPath.Path)
- }
- break
- case v1.HostPathFileOrCreate:
- if _, err := os.Stat(hostPath.Path); os.IsNotExist(err) {
- f, err := os.OpenFile(hostPath.Path, os.O_RDONLY|os.O_CREATE, createFilePermission)
- if err != nil {
- return pod, errors.Errorf("Error creating HostPath %s at %s", volume.Name, hostPath.Path)
- }
- if err := f.Close(); err != nil {
- logrus.Warnf("Error in closing newly created HostPath file: %v", err)
- }
- }
- // unconditionally label a newly created volume as private
- if err := libpod.LabelVolumePath(hostPath.Path, false); err != nil {
- return pod, errors.Wrapf(err, "Error giving %s a label", hostPath.Path)
- }
- break
- case v1.HostPathDirectory:
- case v1.HostPathFile:
- case v1.HostPathUnset:
- // do nothing here because we will verify the path exists in validateVolumeHostDir
- break
- default:
- return pod, errors.Errorf("Directories are the only supported HostPath type")
- }
- }
-
- if err := createconfig.ValidateVolumeHostDir(hostPath.Path); err != nil {
- return pod, errors.Wrapf(err, "Error in parsing HostPath in YAML")
- }
- volumes[volume.Name] = hostPath.Path
- }
-
- for _, container := range podYAML.Spec.Containers {
- newImage, err := runtime.ImageRuntime().New(ctx, container.Image, c.SignaturePolicy, c.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, false, nil)
- if err != nil {
- return pod, err
- }
- createConfig, err := kubeContainerToCreateConfig(ctx, container, runtime, newImage, namespaces, volumes, pod.ID())
- if err != nil {
- return pod, err
- }
- ctr, err := shared.CreateContainerFromCreateConfig(runtime, createConfig, ctx, pod)
- if err != nil {
- return pod, err
- }
- containers = append(containers, ctr)
- }
-
- // start the containers
- for _, ctr := range containers {
- if err := ctr.Start(ctx, true); err != nil {
- // Making this a hard failure here to avoid a mess
- // the other containers are in created status
- return pod, err
- }
- }
-
- // We've now successfully converted this YAML into a pod
- // print our pod and containers, signifying we succeeded
- fmt.Printf("Pod:\n%s\n", pod.ID())
- if len(containers) == 1 {
- fmt.Printf("Container:\n")
- }
- if len(containers) > 1 {
- fmt.Printf("Containers:\n")
- }
- for _, ctr := range containers {
- fmt.Println(ctr.ID())
- }
-
- return pod, nil
-}
-
-// getPodPorts converts a slice of kube container descriptions to an
-// array of ocicni portmapping descriptions usable in libpod
-func getPodPorts(containers []v1.Container) []ocicni.PortMapping {
- var infraPorts []ocicni.PortMapping
- for _, container := range containers {
- for _, p := range container.Ports {
- portBinding := ocicni.PortMapping{
- HostPort: p.HostPort,
- ContainerPort: p.ContainerPort,
- Protocol: strings.ToLower(string(p.Protocol)),
- }
- if p.HostIP != "" {
- logrus.Debug("HostIP on port bindings is not supported")
- }
- infraPorts = append(infraPorts, portBinding)
- }
- }
- return infraPorts
-}
-
-// kubeContainerToCreateConfig takes a v1.Container and returns a createconfig describing a container
-func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container, runtime *libpod.Runtime, newImage *image.Image, namespaces map[string]string, volumes map[string]string, podID string) (*createconfig.CreateConfig, error) {
- var (
- containerConfig createconfig.CreateConfig
- )
-
- // The default for MemorySwappiness is -1, not 0
- containerConfig.Resources.MemorySwappiness = -1
-
- containerConfig.Image = containerYAML.Image
- containerConfig.ImageID = newImage.ID()
- containerConfig.Name = containerYAML.Name
- containerConfig.Tty = containerYAML.TTY
- containerConfig.WorkDir = containerYAML.WorkingDir
-
- containerConfig.Pod = podID
-
- 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
- }
- if containerYAML.SecurityContext.Privileged != nil {
- containerConfig.Privileged = *containerYAML.SecurityContext.Privileged
- }
-
- if containerYAML.SecurityContext.AllowPrivilegeEscalation != nil {
- containerConfig.NoNewPrivs = !*containerYAML.SecurityContext.AllowPrivilegeEscalation
- }
- }
-
- containerConfig.Command = []string{}
- if imageData != nil && imageData.Config != nil {
- containerConfig.Command = append(containerConfig.Command, imageData.Config.Entrypoint...)
- }
- if len(containerConfig.Command) != 0 {
- containerConfig.Command = append(containerConfig.Command, containerYAML.Command...)
- } else if imageData != nil && imageData.Config != nil {
- containerConfig.Command = append(containerConfig.Command, imageData.Config.Cmd...)
- }
- if imageData != nil && len(containerConfig.Command) == 0 {
- return nil, errors.Errorf("No command specified in container YAML or as CMD or ENTRYPOINT in this image for %s", containerConfig.Name)
- }
-
- containerConfig.StopSignal = 15
-
- // If the user does not pass in ID mappings, just set to basics
- if containerConfig.IDMappings == nil {
- containerConfig.IDMappings = &storage.IDMappingOptions{}
- }
-
- containerConfig.NetMode = ns.NetworkMode(namespaces["net"])
- containerConfig.IpcMode = ns.IpcMode(namespaces["ipc"])
- containerConfig.UtsMode = ns.UTSMode(namespaces["uts"])
- // disabled in code review per mheon
- //containerConfig.PidMode = ns.PidMode(namespaces["pid"])
- containerConfig.UsernsMode = ns.UsernsMode(namespaces["user"])
- if len(containerConfig.WorkDir) == 0 {
- containerConfig.WorkDir = "/"
- }
-
- // Set default environment variables and incorporate data from image, if necessary
- envs := shared.EnvVariablesFromData(imageData)
-
- // Environment Variables
- for _, e := range containerYAML.Env {
- envs[e.Name] = e.Value
- }
- containerConfig.Env = envs
-
- for _, volume := range containerYAML.VolumeMounts {
- host_path, exists := volumes[volume.Name]
- if !exists {
- return nil, errors.Errorf("Volume mount %s specified for container but not configured in volumes", volume.Name)
- }
- if err := createconfig.ValidateVolumeCtrDir(volume.MountPath); err != nil {
- return nil, errors.Wrapf(err, "error in parsing MountPath")
- }
- containerConfig.Volumes = append(containerConfig.Volumes, fmt.Sprintf("%s:%s", host_path, volume.MountPath))
- }
- return &containerConfig, nil
-}
diff --git a/cmd/podman/pod_create.go b/cmd/podman/pod_create.go
index c891f2c7b..b6154b4db 100644
--- a/cmd/podman/pod_create.go
+++ b/cmd/podman/pod_create.go
@@ -6,8 +6,10 @@ import (
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/shared"
- "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/adapter"
+ "github.com/containers/libpod/pkg/errorhandling"
+ "github.com/containers/libpod/pkg/util"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -45,8 +47,8 @@ func init() {
flags.StringVar(&podCreateCommand.CgroupParent, "cgroup-parent", "", "Set parent cgroup for the pod")
flags.BoolVar(&podCreateCommand.Infra, "infra", true, "Create an infra container associated with the pod to share namespaces with")
- flags.StringVar(&podCreateCommand.InfraImage, "infra-image", libpod.DefaultInfraImage, "The image of the infra container to associate with the pod")
- flags.StringVar(&podCreateCommand.InfraCommand, "infra-command", libpod.DefaultInfraCommand, "The command to run on the infra container when the pod is started")
+ flags.StringVar(&podCreateCommand.InfraImage, "infra-image", define.DefaultInfraImage, "The image of the infra container to associate with the pod")
+ flags.StringVar(&podCreateCommand.InfraCommand, "infra-command", define.DefaultInfraCommand, "The command to run on the infra container when the pod is started")
flags.StringSliceVar(&podCreateCommand.LabelFile, "label-file", []string{}, "Read in a line delimited file of labels")
flags.StringSliceVarP(&podCreateCommand.Labels, "label", "l", []string{}, "Set metadata on pod (default [])")
flags.StringVarP(&podCreateCommand.Name, "name", "n", "", "Assign a name to the pod")
@@ -55,7 +57,6 @@ func init() {
flags.StringVar(&podCreateCommand.Share, "share", shared.DefaultKernelNamespaces, "A comma delimited list of kernel namespaces the pod will share")
}
-
func podCreateCmd(c *cliconfig.PodCreateValues) error {
var (
err error
@@ -66,7 +67,7 @@ func podCreateCmd(c *cliconfig.PodCreateValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
if len(c.Publish) > 0 {
if !c.Infra {
@@ -78,15 +79,15 @@ func podCreateCmd(c *cliconfig.PodCreateValues) error {
return errors.Errorf("You cannot share kernel namespaces on the pod level without an infra container")
}
if c.Flag("pod-id-file").Changed && os.Geteuid() == 0 {
- podIdFile, err = libpod.OpenExclusiveFile(c.PodIDFile)
+ podIdFile, err = util.OpenExclusiveFile(c.PodIDFile)
if err != nil && os.IsExist(err) {
return errors.Errorf("pod id file exists. Ensure another pod is not using it or delete %s", c.PodIDFile)
}
if err != nil {
return errors.Errorf("error opening pod-id-file %s", c.PodIDFile)
}
- defer podIdFile.Close()
- defer podIdFile.Sync()
+ defer errorhandling.CloseQuiet(podIdFile)
+ defer errorhandling.SyncQuiet(podIdFile)
}
labels, err := shared.GetAllLabels(c.LabelFile, c.Labels)
diff --git a/cmd/podman/pod_inspect.go b/cmd/podman/pod_inspect.go
index a22624078..03b5a8cc4 100644
--- a/cmd/podman/pod_inspect.go
+++ b/cmd/podman/pod_inspect.go
@@ -53,7 +53,7 @@ func podInspectCmd(c *cliconfig.PodInspectValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
if c.Latest {
pod, err = runtime.GetLatestPod()
diff --git a/cmd/podman/pod_kill.go b/cmd/podman/pod_kill.go
index c1ea66126..9bda77471 100644
--- a/cmd/podman/pod_kill.go
+++ b/cmd/podman/pod_kill.go
@@ -53,9 +53,9 @@ func podKillCmd(c *cliconfig.PodKillValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
- var killSignal uint = uint(syscall.SIGTERM)
+ killSignal := uint(syscall.SIGTERM)
if c.Signal != "" {
// Check if the signalString provided by the user is valid
diff --git a/cmd/podman/pod_pause.go b/cmd/podman/pod_pause.go
index e8574bfdc..45e1319ff 100644
--- a/cmd/podman/pod_pause.go
+++ b/cmd/podman/pod_pause.go
@@ -49,14 +49,14 @@ func podPauseCmd(c *cliconfig.PodPauseValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
pauseIDs, conErrors, pauseErrors := runtime.PausePods(c)
for _, p := range pauseIDs {
fmt.Println(p)
}
- if conErrors != nil && len(conErrors) > 0 {
+ if len(conErrors) > 0 {
for ctr, err := range conErrors {
if lastError != nil {
logrus.Errorf("%q", lastError)
diff --git a/cmd/podman/pod_ps.go b/cmd/podman/pod_ps.go
index b9dcbc05d..bda447c57 100644
--- a/cmd/podman/pod_ps.go
+++ b/cmd/podman/pod_ps.go
@@ -11,7 +11,7 @@ import (
"github.com/containers/buildah/pkg/formats"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/shared"
- "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/adapter"
"github.com/containers/libpod/pkg/util"
"github.com/docker/go-units"
@@ -20,7 +20,7 @@ import (
)
const (
- STOPPED = "Stopped"
+ STOPPED = "Stopped" //nolint
RUNNING = "Running"
PAUSED = "Paused"
EXITED = "Exited"
@@ -36,9 +36,9 @@ var (
)
type podPsCtrInfo struct {
- Name string `"json:name,omitempty"`
- Id string `"json:id,omitempty"`
- Status string `"json:status,omitempty"`
+ Name string `json:"name,omitempty"`
+ Id string `json:"id,omitempty"`
+ Status string `json:"status,omitempty"`
}
type podPsOptions struct {
@@ -161,7 +161,7 @@ func podPsCmd(c *cliconfig.PodPsValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
opts := podPsOptions{
NoTrunc: c.NoTrunc,
@@ -282,7 +282,7 @@ func generatePodFilterFuncs(filter, filterValue string) (func(pod *adapter.Pod)
}
for _, ctr_status := range ctr_statuses {
state := ctr_status.String()
- if ctr_status == libpod.ContainerStateConfigured {
+ if ctr_status == define.ContainerStateConfigured {
state = "created"
}
if state == filterValue {
@@ -504,15 +504,15 @@ func getAndSortPodJSONParams(pods []*adapter.Pod, opts podPsOptions) ([]podPsJSO
}
var status string
switch batchInfo.ConState {
- case libpod.ContainerStateExited:
+ case define.ContainerStateExited:
fallthrough
- case libpod.ContainerStateStopped:
+ case define.ContainerStateStopped:
status = EXITED
- case libpod.ContainerStateRunning:
+ case define.ContainerStateRunning:
status = RUNNING
- case libpod.ContainerStatePaused:
+ case define.ContainerStatePaused:
status = PAUSED
- case libpod.ContainerStateCreated, libpod.ContainerStateConfigured:
+ case define.ContainerStateCreated, define.ContainerStateConfigured:
status = CREATED
default:
status = ERROR
@@ -552,9 +552,6 @@ func generatePodPsOutput(pods []*adapter.Pod, opts podPsOptions) error {
switch opts.Format {
case formats.JSONString:
- if err != nil {
- return errors.Wrapf(err, "unable to create JSON for output")
- }
out = formats.JSONStructArray{Output: podPsToGeneric([]podPsTemplateParams{}, psOutput)}
default:
psOutput, err := getPodTemplateOutput(psOutput, opts)
@@ -564,5 +561,5 @@ func generatePodPsOutput(pods []*adapter.Pod, opts podPsOptions) error {
out = formats.StdoutTemplateArray{Output: podPsToGeneric(psOutput, []podPsJSONParams{}), Template: opts.Format, Fields: psOutput[0].podHeaderMap()}
}
- return formats.Writer(out).Out()
+ return out.Out()
}
diff --git a/cmd/podman/pod_restart.go b/cmd/podman/pod_restart.go
index a1f4c8359..cc090bd6e 100644
--- a/cmd/podman/pod_restart.go
+++ b/cmd/podman/pod_restart.go
@@ -51,14 +51,14 @@ func podRestartCmd(c *cliconfig.PodRestartValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
restartIDs, conErrors, restartErrors := runtime.RestartPods(getContext(), c)
for _, p := range restartIDs {
fmt.Println(p)
}
- if conErrors != nil && len(conErrors) > 0 {
+ if len(conErrors) > 0 {
for ctr, err := range conErrors {
if lastError != nil {
logrus.Errorf("%q", lastError)
diff --git a/cmd/podman/pod_rm.go b/cmd/podman/pod_rm.go
index 218ed8154..82d0eb977 100644
--- a/cmd/podman/pod_rm.go
+++ b/cmd/podman/pod_rm.go
@@ -51,7 +51,7 @@ func podRmCmd(c *cliconfig.PodRmValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
podRmIds, podRmErrors := runtime.RemovePods(getContext(), c)
for _, p := range podRmIds {
diff --git a/cmd/podman/pod_start.go b/cmd/podman/pod_start.go
index 5c9225428..64c951b43 100644
--- a/cmd/podman/pod_start.go
+++ b/cmd/podman/pod_start.go
@@ -49,7 +49,7 @@ func podStartCmd(c *cliconfig.PodStartValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
podStartIDs, podStartErrors := runtime.StartPods(getContext(), c)
for _, p := range podStartIDs {
diff --git a/cmd/podman/pod_stats.go b/cmd/podman/pod_stats.go
index e0e5ca24e..46cacc026 100644
--- a/cmd/podman/pod_stats.go
+++ b/cmd/podman/pod_stats.go
@@ -13,6 +13,7 @@ import (
"github.com/containers/buildah/pkg/formats"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/adapter"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -73,16 +74,13 @@ func podStatsCmd(c *cliconfig.PodStatsValues) error {
if ctr > 1 {
return errors.Errorf("--all, --latest and containers cannot be used together")
- } else if ctr == 0 {
- // If user didn't specify, imply --all
- all = true
}
runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
times := -1
if c.NoStream {
@@ -93,24 +91,6 @@ func podStatsCmd(c *cliconfig.PodStatsValues) error {
if err != nil {
return errors.Wrapf(err, "unable to get a list of pods")
}
- // First we need to get an initial pass of pod/ctr stats (these are not printed)
- var podStats []*adapter.PodContainerStats
- for _, p := range pods {
- cons, err := p.AllContainersByID()
- if err != nil {
- return err
- }
- emptyStats := make(map[string]*libpod.ContainerStats)
- // Iterate the pods container ids and make blank stats for them
- for _, c := range cons {
- emptyStats[c] = &libpod.ContainerStats{}
- }
- ps := adapter.PodContainerStats{
- Pod: p,
- ContainerStats: emptyStats,
- }
- podStats = append(podStats, &ps)
- }
// Create empty container stat results for our first pass
var previousPodStats []*adapter.PodContainerStats
@@ -153,7 +133,7 @@ func podStatsCmd(c *cliconfig.PodStatsValues) error {
for _, p := range pods {
prevStat := getPreviousPodContainerStats(p.ID(), previousPodStats)
newPodStats, err := p.GetPodStats(prevStat)
- if errors.Cause(err) == libpod.ErrNoSuchPod {
+ if errors.Cause(err) == define.ErrNoSuchPod {
continue
}
if err != nil {
@@ -172,7 +152,9 @@ func podStatsCmd(c *cliconfig.PodStatsValues) error {
tm.Flush()
}
if strings.ToLower(format) == formats.JSONString {
- outputJson(newStats)
+ if err := outputJson(newStats); err != nil {
+ return err
+ }
} else {
results := podContainerStatsToPodStatOut(newStats)
@@ -270,7 +252,7 @@ func printPSFormat(format string, stats []*podStatOut, headerNames map[string]st
func outputToStdOut(stats []*podStatOut) {
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
- outFormat := ("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n")
+ outFormat := "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n"
fmt.Fprintf(w, outFormat, "POD", "CID", "NAME", "CPU %", "MEM USAGE/ LIMIT", "MEM %", "NET IO", "BLOCK IO", "PIDS")
for _, i := range stats {
if len(stats) == 0 {
@@ -299,17 +281,3 @@ func outputJson(stats []*adapter.PodContainerStats) error {
fmt.Println(string(b))
return nil
}
-
-func getPodsByList(podList []string, r *libpod.Runtime) ([]*libpod.Pod, error) {
- var (
- pods []*libpod.Pod
- )
- for _, p := range podList {
- pod, err := r.LookupPod(p)
- if err != nil {
- return nil, err
- }
- pods = append(pods, pod)
- }
- return pods, nil
-}
diff --git a/cmd/podman/pod_stop.go b/cmd/podman/pod_stop.go
index b4b1718d9..edda99550 100644
--- a/cmd/podman/pod_stop.go
+++ b/cmd/podman/pod_stop.go
@@ -51,7 +51,7 @@ func podStopCmd(c *cliconfig.PodStopValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
podStopIds, podStopErrors := runtime.StopPods(getContext(), c)
for _, p := range podStopIds {
diff --git a/cmd/podman/pod_top.go b/cmd/podman/pod_top.go
index 64e32318e..fcd9c4f3c 100644
--- a/cmd/podman/pod_top.go
+++ b/cmd/podman/pod_top.go
@@ -2,13 +2,13 @@ package main
import (
"fmt"
- "github.com/containers/libpod/pkg/adapter"
"os"
"strings"
"text/tabwriter"
"github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/adapter"
+ "github.com/containers/libpod/pkg/util"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@@ -44,8 +44,7 @@ func init() {
flags := podTopCommand.Flags()
flags.BoolVarP(&podTopCommand.Latest, "latest,", "l", false, "Act on the latest pod podman is aware of")
flags.BoolVar(&podTopCommand.ListDescriptors, "list-descriptors", false, "")
- flags.MarkHidden("list-descriptors")
-
+ markFlagHidden(flags, "list-descriptors")
}
func podTopCmd(c *cliconfig.PodTopValues) error {
@@ -55,7 +54,7 @@ func podTopCmd(c *cliconfig.PodTopValues) error {
args := c.InputArgs
if c.ListDescriptors {
- descriptors, err := libpod.GetContainerPidInformationDescriptors()
+ descriptors, err := util.GetContainerPidInformationDescriptors()
if err != nil {
return err
}
@@ -71,7 +70,7 @@ func podTopCmd(c *cliconfig.PodTopValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
if c.Latest {
descriptors = args
@@ -85,8 +84,9 @@ func podTopCmd(c *cliconfig.PodTopValues) error {
return err
}
for _, proc := range psOutput {
- fmt.Fprintln(w, proc)
+ if _, err := fmt.Fprintln(w, proc); err != nil {
+ return err
+ }
}
- w.Flush()
- return nil
+ return w.Flush()
}
diff --git a/cmd/podman/pod_unpause.go b/cmd/podman/pod_unpause.go
index c5b7e6a18..833434c3f 100644
--- a/cmd/podman/pod_unpause.go
+++ b/cmd/podman/pod_unpause.go
@@ -50,14 +50,14 @@ func podUnpauseCmd(c *cliconfig.PodUnpauseValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
unpauseIDs, conErrors, unpauseErrors := runtime.UnpausePods(c)
for _, p := range unpauseIDs {
fmt.Println(p)
}
- if conErrors != nil && len(conErrors) > 0 {
+ if len(conErrors) > 0 {
for ctr, err := range conErrors {
if lastError != nil {
logrus.Errorf("%q", lastError)
diff --git a/cmd/podman/pods_prune.go b/cmd/podman/pods_prune.go
index bdd75f9de..d40e37bdb 100644
--- a/cmd/podman/pods_prune.go
+++ b/cmd/podman/pods_prune.go
@@ -40,8 +40,11 @@ func podPruneCmd(c *cliconfig.PodPruneValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
ok, failures, err := runtime.PrunePods(getContext(), c)
+ if err != nil {
+ return err
+ }
return printCmdResults(ok, failures)
}
diff --git a/cmd/podman/port.go b/cmd/podman/port.go
index 1bd2d623e..5753c8e56 100644
--- a/cmd/podman/port.go
+++ b/cmd/podman/port.go
@@ -95,9 +95,12 @@ func portCmd(c *cliconfig.PortValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
containers, err := runtime.Port(c)
+ if err != nil {
+ return err
+ }
for _, con := range containers {
portmappings, err := con.PortMappings()
if err != nil {
diff --git a/cmd/podman/ps.go b/cmd/podman/ps.go
index eb5181126..9fad0ea65 100644
--- a/cmd/podman/ps.go
+++ b/cmd/podman/ps.go
@@ -15,87 +15,32 @@ import (
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/pkg/adapter"
- "github.com/cri-o/ocicni/pkg/ocicni"
"github.com/docker/go-units"
"github.com/pkg/errors"
"github.com/spf13/cobra"
- "k8s.io/apimachinery/pkg/fields"
)
const (
- mountTruncLength = 12
- hid = "CONTAINER ID"
- himage = "IMAGE"
- hcommand = "COMMAND"
- hcreated = "CREATED"
- hstatus = "STATUS"
- hports = "PORTS"
- hnames = "NAMES"
- hsize = "SIZE"
- hinfra = "IS INFRA"
- hpod = "POD"
- nspid = "PID"
- nscgroup = "CGROUPNS"
- nsipc = "IPC"
- nsmnt = "MNT"
- nsnet = "NET"
- nspidns = "PIDNS"
- nsuserns = "USERNS"
- nsuts = "UTS"
+ hid = "CONTAINER ID"
+ himage = "IMAGE"
+ hcommand = "COMMAND"
+ hcreated = "CREATED"
+ hstatus = "STATUS"
+ hports = "PORTS"
+ hnames = "NAMES"
+ hsize = "SIZE"
+ hinfra = "IS INFRA" //nolint
+ hpod = "POD"
+ nspid = "PID"
+ nscgroup = "CGROUPNS"
+ nsipc = "IPC"
+ nsmnt = "MNT"
+ nsnet = "NET"
+ nspidns = "PIDNS"
+ nsuserns = "USERNS"
+ nsuts = "UTS"
)
-type psTemplateParams struct {
- ID string
- Image string
- Command string
- CreatedAtTime time.Time
- Created string
- Status string
- Ports string
- Size string
- Names string
- Labels string
- Mounts string
- PID int
- CGROUPNS string
- IPC string
- MNT string
- NET string
- PIDNS string
- USERNS string
- UTS string
- Pod string
- IsInfra bool
-}
-
-// psJSONParams is used as a base structure for the psParams
-// If template output is requested, psJSONParams will be converted to
-// psTemplateParams.
-// psJSONParams will be populated by data from libpod.Container,
-// the members of the struct are the sama data types as their sources.
-type psJSONParams struct {
- ID string `json:"id"`
- Image string `json:"image"`
- ImageID string `json:"image_id"`
- Command []string `json:"command"`
- ExitCode int32 `json:"exitCode"`
- Exited bool `json:"exited"`
- CreatedAt time.Time `json:"createdAt"`
- StartedAt time.Time `json:"startedAt"`
- ExitedAt time.Time `json:"exitedAt"`
- Status string `json:"status"`
- PID int `json:"PID"`
- Ports []ocicni.PortMapping `json:"ports"`
- Size *shared.ContainerSize `json:"size,omitempty"`
- Names string `json:"names"`
- Labels fields.Set `json:"labels"`
- Mounts []string `json:"mounts"`
- ContainerRunning bool `json:"ctrRunning"`
- Namespaces *shared.Namespace `json:"namespace,omitempty"`
- Pod string `json:"pod,omitempty"`
- IsInfra bool `json:"infra"`
-}
-
// Type declaration and functions for sorting the PS output
type psSorted []shared.PsContainerOutput
@@ -197,7 +142,11 @@ func init() {
}
func psCmd(c *cliconfig.PsValues) error {
- var watch bool
+ var (
+ watch bool
+ runtime *adapter.LocalRuntime
+ err error
+ )
if c.Watch > 0 {
watch = true
@@ -210,13 +159,16 @@ func psCmd(c *cliconfig.PsValues) error {
if err := checkFlagsPassed(c); err != nil {
return errors.Wrapf(err, "error with flags passed")
}
-
- runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand)
+ if !c.Size {
+ runtime, err = adapter.GetRuntimeNoStore(getContext(), &c.PodmanCommand)
+ } else {
+ runtime, err = adapter.GetRuntime(getContext(), &c.PodmanCommand)
+ }
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
if !watch {
if err := psDisplay(c, runtime); err != nil {
@@ -266,22 +218,6 @@ func checkFlagsPassed(c *cliconfig.PsValues) error {
return nil
}
-// generate the accurate header based on template given
-func (p *psTemplateParams) headerMap() map[string]string {
- v := reflect.Indirect(reflect.ValueOf(p))
- values := make(map[string]string)
-
- for i := 0; i < v.NumField(); i++ {
- key := v.Type().Field(i).Name
- value := key
- if value == "ID" {
- value = "Container" + value
- }
- values[key] = strings.ToUpper(splitCamelCase(value))
- }
- return values
-}
-
func sortPsOutput(sortBy string, psOutput psSorted) (psSorted, error) {
switch sortBy {
case "id":
@@ -308,57 +244,6 @@ func sortPsOutput(sortBy string, psOutput psSorted) (psSorted, error) {
return psOutput, nil
}
-// getLabels converts the labels to a string of the form "key=value, key2=value2"
-func formatLabels(labels map[string]string) string {
- var arr []string
- if len(labels) > 0 {
- for key, val := range labels {
- temp := key + "=" + val
- arr = append(arr, temp)
- }
- return strings.Join(arr, ",")
- }
- return ""
-}
-
-// getMounts converts the volumes mounted to a string of the form "mount1, mount2"
-// it truncates it if noTrunc is false
-func getMounts(mounts []string, noTrunc bool) string {
- return strings.Join(getMountsArray(mounts, noTrunc), ",")
-}
-
-func getMountsArray(mounts []string, noTrunc bool) []string {
- var arr []string
- if len(mounts) == 0 {
- return mounts
- }
- for _, mount := range mounts {
- splitArr := strings.Split(mount, ":")
- if len(splitArr[0]) > mountTruncLength && !noTrunc {
- arr = append(arr, splitArr[0][:mountTruncLength]+"...")
- continue
- }
- arr = append(arr, splitArr[0])
- }
- return arr
-}
-
-// portsToString converts the ports used to a string of the from "port1, port2"
-func portsToString(ports []ocicni.PortMapping) string {
- var portDisplay []string
- if len(ports) == 0 {
- return ""
- }
- 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))
- }
- return strings.Join(portDisplay, ", ")
-}
-
func printFormat(format string, containers []shared.PsContainerOutput) error {
// return immediately if no containers are present
if len(containers) == 0 {
@@ -434,6 +319,9 @@ func psDisplay(c *cliconfig.PsValues, runtime *adapter.LocalRuntime) error {
}
pss, err := runtime.Ps(c, opts)
+ if err != nil {
+ return err
+ }
// Here and down
if opts.Sort != "" {
pss, err = sortPsOutput(opts.Sort, pss)
@@ -491,8 +379,8 @@ func psDisplay(c *cliconfig.PsValues, runtime *adapter.LocalRuntime) error {
size = units.HumanSizeWithPrecision(0, 0)
} else {
size = units.HumanSizeWithPrecision(float64(container.Size.RwSize), 3) + " (virtual " + units.HumanSizeWithPrecision(float64(container.Size.RootFsSize), 3) + ")"
- fmt.Fprintf(w, "\t%s", size)
}
+ fmt.Fprintf(w, "\t%s", size)
}
} else {
diff --git a/cmd/podman/pull.go b/cmd/podman/pull.go
index 115f437d8..0eee51e79 100644
--- a/cmd/podman/pull.go
+++ b/cmd/podman/pull.go
@@ -11,10 +11,11 @@ import (
"github.com/containers/image/transports/alltransports"
"github.com/containers/image/types"
"github.com/containers/libpod/cmd/podman/cliconfig"
+ "github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/adapter"
"github.com/containers/libpod/pkg/util"
- opentracing "github.com/opentracing/opentracing-go"
+ "github.com/opentracing/opentracing-go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -55,11 +56,11 @@ func init() {
flags.BoolVarP(&pullCommand.Quiet, "quiet", "q", false, "Suppress output information when pulling images")
// Disabled flags for the remote client
if !remote {
- flags.StringVar(&pullCommand.Authfile, "authfile", getAuthFile(""), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
+ flags.StringVar(&pullCommand.Authfile, "authfile", shared.GetAuthFile(""), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
flags.StringVar(&pullCommand.CertDir, "cert-dir", "", "`Pathname` of a directory containing TLS certificates and keys")
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")
- flags.MarkHidden("signature-policy")
+ markFlagHidden(flags, "signature-policy")
}
}
@@ -81,7 +82,7 @@ func pullCmd(c *cliconfig.PullValues) (retError error) {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
args := c.InputArgs
if len(args) == 0 {
diff --git a/cmd/podman/push.go b/cmd/podman/push.go
index 497820156..43df8c2de 100644
--- a/cmd/podman/push.go
+++ b/cmd/podman/push.go
@@ -10,6 +10,7 @@ import (
"github.com/containers/image/manifest"
"github.com/containers/image/types"
"github.com/containers/libpod/cmd/podman/cliconfig"
+ "github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/adapter"
"github.com/containers/libpod/pkg/util"
@@ -57,12 +58,12 @@ func init() {
// Disabled flags for the remote client
if !remote {
- flags.StringVar(&pushCommand.Authfile, "authfile", getAuthFile(""), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
+ flags.StringVar(&pushCommand.Authfile, "authfile", shared.GetAuthFile(""), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
flags.StringVar(&pushCommand.CertDir, "cert-dir", "", "`Pathname` of a directory containing TLS certificates and keys")
flags.BoolVar(&pushCommand.Compress, "compress", false, "Compress tarball image layers when pushing to a directory using the 'dir' transport. (default is same compression type as source)")
flags.StringVar(&pushCommand.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)")
flags.BoolVar(&pushCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries")
- flags.MarkHidden("signature-policy")
+ markFlagHidden(flags, "signature-policy")
}
}
@@ -108,7 +109,7 @@ func pushCmd(c *cliconfig.PushValues) error {
if err != nil {
return errors.Wrapf(err, "could not create runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
var writer io.Writer
if !c.Quiet {
diff --git a/cmd/podman/refresh.go b/cmd/podman/refresh.go
index 9f9cbf908..b21a4ff79 100644
--- a/cmd/podman/refresh.go
+++ b/cmd/podman/refresh.go
@@ -42,7 +42,7 @@ func refreshCmd(c *cliconfig.RefreshValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
allCtrs, err := runtime.GetAllContainers()
if err != nil {
diff --git a/cmd/podman/remoteclientconfig/config.go b/cmd/podman/remoteclientconfig/config.go
new file mode 100644
index 000000000..01f293ec3
--- /dev/null
+++ b/cmd/podman/remoteclientconfig/config.go
@@ -0,0 +1,21 @@
+package remoteclientconfig
+
+const remoteConfigFileName string = "podman-remote.conf"
+
+// RemoteConfig describes the podman remote configuration file
+type RemoteConfig struct {
+ Connections map[string]RemoteConnection
+}
+
+// RemoteConnection describes the attributes of a podman-remote endpoint
+type RemoteConnection struct {
+ Destination string `toml:"destination"`
+ Username string `toml:"username"`
+ IsDefault bool `toml:"default"`
+}
+
+// GetConfigFilePath is a simple helper to export the configuration file's
+// path based on arch, etc
+func GetConfigFilePath() string {
+ return getConfigFilePath()
+}
diff --git a/cmd/podman/remoteclientconfig/config_darwin.go b/cmd/podman/remoteclientconfig/config_darwin.go
new file mode 100644
index 000000000..b94941381
--- /dev/null
+++ b/cmd/podman/remoteclientconfig/config_darwin.go
@@ -0,0 +1,12 @@
+package remoteclientconfig
+
+import (
+ "path/filepath"
+
+ "github.com/docker/docker/pkg/homedir"
+)
+
+func getConfigFilePath() string {
+ homeDir := homedir.Get()
+ return filepath.Join(homeDir, ".config", "containers", remoteConfigFileName)
+}
diff --git a/cmd/podman/remoteclientconfig/config_linux.go b/cmd/podman/remoteclientconfig/config_linux.go
new file mode 100644
index 000000000..b94941381
--- /dev/null
+++ b/cmd/podman/remoteclientconfig/config_linux.go
@@ -0,0 +1,12 @@
+package remoteclientconfig
+
+import (
+ "path/filepath"
+
+ "github.com/docker/docker/pkg/homedir"
+)
+
+func getConfigFilePath() string {
+ homeDir := homedir.Get()
+ return filepath.Join(homeDir, ".config", "containers", remoteConfigFileName)
+}
diff --git a/cmd/podman/remoteclientconfig/config_windows.go b/cmd/podman/remoteclientconfig/config_windows.go
new file mode 100644
index 000000000..fa6ffca63
--- /dev/null
+++ b/cmd/podman/remoteclientconfig/config_windows.go
@@ -0,0 +1,12 @@
+package remoteclientconfig
+
+import (
+ "path/filepath"
+
+ "github.com/docker/docker/pkg/homedir"
+)
+
+func getConfigFilePath() string {
+ homeDir := homedir.Get()
+ return filepath.Join(homeDir, "AppData", "podman", remoteConfigFileName)
+}
diff --git a/cmd/podman/remoteclientconfig/configfile.go b/cmd/podman/remoteclientconfig/configfile.go
new file mode 100644
index 000000000..56a868733
--- /dev/null
+++ b/cmd/podman/remoteclientconfig/configfile.go
@@ -0,0 +1,64 @@
+package remoteclientconfig
+
+import (
+ "io"
+
+ "github.com/BurntSushi/toml"
+ "github.com/pkg/errors"
+)
+
+// ReadRemoteConfig takes an io.Reader representing the remote configuration
+// file and returns a remoteconfig
+func ReadRemoteConfig(reader io.Reader) (*RemoteConfig, error) {
+ var remoteConfig RemoteConfig
+ // the configuration file does not exist
+ if reader == nil {
+ return &remoteConfig, ErrNoConfigationFile
+ }
+ _, err := toml.DecodeReader(reader, &remoteConfig)
+ if err != nil {
+ return nil, err
+ }
+ // We need to validate each remote connection has fields filled out
+ for name, conn := range remoteConfig.Connections {
+ if len(conn.Destination) < 1 {
+ return nil, errors.Errorf("connection %q has no destination defined", name)
+ }
+ }
+ return &remoteConfig, err
+}
+
+// GetDefault returns the default RemoteConnection. If there is only one
+// connection, we assume it is the default as well
+func (r *RemoteConfig) GetDefault() (*RemoteConnection, error) {
+ if len(r.Connections) == 0 {
+ return nil, ErrNoDefinedConnections
+ }
+ for _, v := range r.Connections {
+ v := v
+ if len(r.Connections) == 1 {
+ // if there is only one defined connection, we assume it is
+ // the default whether tagged as such or not
+ return &v, nil
+ }
+ if v.IsDefault {
+ return &v, nil
+ }
+ }
+ return nil, ErrNoDefaultConnection
+}
+
+// GetRemoteConnection "looks up" a remote connection by name and returns it in the
+// form of a RemoteConnection
+func (r *RemoteConfig) GetRemoteConnection(name string) (*RemoteConnection, error) {
+ if len(r.Connections) == 0 {
+ return nil, ErrNoDefinedConnections
+ }
+ for k, v := range r.Connections {
+ v := v
+ if k == name {
+ return &v, nil
+ }
+ }
+ return nil, errors.Wrap(ErrConnectionNotFound, name)
+}
diff --git a/cmd/podman/remoteclientconfig/configfile_test.go b/cmd/podman/remoteclientconfig/configfile_test.go
new file mode 100644
index 000000000..66e0a4693
--- /dev/null
+++ b/cmd/podman/remoteclientconfig/configfile_test.go
@@ -0,0 +1,201 @@
+package remoteclientconfig
+
+import (
+ "io"
+ "reflect"
+ "strings"
+ "testing"
+)
+
+var goodConfig = `
+[connections]
+
+[connections.homer]
+destination = "192.168.1.1"
+username = "myuser"
+default = true
+
+[connections.bart]
+destination = "foobar.com"
+username = "root"
+`
+var noDest = `
+[connections]
+
+[connections.homer]
+destination = "192.168.1.1"
+username = "myuser"
+default = true
+
+[connections.bart]
+username = "root"
+`
+
+var noUser = `
+[connections]
+
+[connections.homer]
+destination = "192.168.1.1"
+`
+
+func makeGoodResult() *RemoteConfig {
+ var goodConnections = make(map[string]RemoteConnection)
+ goodConnections["homer"] = RemoteConnection{
+ Destination: "192.168.1.1",
+ Username: "myuser",
+ IsDefault: true,
+ }
+ goodConnections["bart"] = RemoteConnection{
+ Destination: "foobar.com",
+ Username: "root",
+ }
+ var goodResult = RemoteConfig{
+ Connections: goodConnections,
+ }
+ return &goodResult
+}
+
+func makeNoUserResult() *RemoteConfig {
+ var goodConnections = make(map[string]RemoteConnection)
+ goodConnections["homer"] = RemoteConnection{
+ Destination: "192.168.1.1",
+ }
+ var goodResult = RemoteConfig{
+ Connections: goodConnections,
+ }
+ return &goodResult
+}
+
+func TestReadRemoteConfig(t *testing.T) {
+ type args struct {
+ reader io.Reader
+ }
+ tests := []struct {
+ name string
+ args args
+ want *RemoteConfig
+ wantErr bool
+ }{
+ // good test should pass
+ {"good", args{reader: strings.NewReader(goodConfig)}, makeGoodResult(), false},
+ // a connection with no destination is an error
+ {"nodest", args{reader: strings.NewReader(noDest)}, nil, true},
+ // a connnection with no user is OK
+ {"nouser", args{reader: strings.NewReader(noUser)}, makeNoUserResult(), false},
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got, err := ReadRemoteConfig(tt.args.reader)
+ if (err != nil) != tt.wantErr {
+ t.Errorf("ReadRemoteConfig() error = %v, wantErr %v", err, tt.wantErr)
+ return
+ }
+ if !reflect.DeepEqual(got, tt.want) {
+ t.Errorf("ReadRemoteConfig() = %v, want %v", got, tt.want)
+ }
+ })
+ }
+}
+
+func TestRemoteConfig_GetDefault(t *testing.T) {
+ good := make(map[string]RemoteConnection)
+ good["homer"] = RemoteConnection{
+ Username: "myuser",
+ Destination: "192.168.1.1",
+ IsDefault: true,
+ }
+ good["bart"] = RemoteConnection{
+ Username: "root",
+ Destination: "foobar.com",
+ }
+ noDefault := make(map[string]RemoteConnection)
+ noDefault["homer"] = RemoteConnection{
+ Username: "myuser",
+ Destination: "192.168.1.1",
+ }
+ noDefault["bart"] = RemoteConnection{
+ Username: "root",
+ Destination: "foobar.com",
+ }
+ single := make(map[string]RemoteConnection)
+ single["homer"] = RemoteConnection{
+ Username: "myuser",
+ Destination: "192.168.1.1",
+ }
+
+ none := make(map[string]RemoteConnection)
+
+ type fields struct {
+ Connections map[string]RemoteConnection
+ }
+ tests := []struct {
+ name string
+ fields fields
+ want *RemoteConnection
+ wantErr bool
+ }{
+ // A good toml should return the connection that is marked isDefault
+ {"good", fields{Connections: makeGoodResult().Connections}, &RemoteConnection{"192.168.1.1", "myuser", true}, false},
+ // If nothing is marked as isDefault and there is more than one connection, error should occur
+ {"nodefault", fields{Connections: noDefault}, nil, true},
+ // if nothing is marked as isDefault but there is only one connection, the one connection is considered the default
+ {"single", fields{Connections: none}, nil, true},
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ r := &RemoteConfig{
+ Connections: tt.fields.Connections,
+ }
+ got, err := r.GetDefault()
+ if (err != nil) != tt.wantErr {
+ t.Errorf("RemoteConfig.GetDefault() error = %v, wantErr %v", err, tt.wantErr)
+ return
+ }
+ if !reflect.DeepEqual(got, tt.want) {
+ t.Errorf("RemoteConfig.GetDefault() = %v, want %v", got, tt.want)
+ }
+ })
+ }
+}
+
+func TestRemoteConfig_GetRemoteConnection(t *testing.T) {
+ type fields struct {
+ Connections map[string]RemoteConnection
+ }
+ type args struct {
+ name string
+ }
+
+ blank := make(map[string]RemoteConnection)
+ tests := []struct {
+ name string
+ fields fields
+ args args
+ want *RemoteConnection
+ wantErr bool
+ }{
+ // Good connection
+ {"goodhomer", fields{Connections: makeGoodResult().Connections}, args{name: "homer"}, &RemoteConnection{"192.168.1.1", "myuser", true}, false},
+ // Good connection
+ {"goodbart", fields{Connections: makeGoodResult().Connections}, args{name: "bart"}, &RemoteConnection{"foobar.com", "root", false}, false},
+ // Getting an unknown connection should result in error
+ {"noexist", fields{Connections: makeGoodResult().Connections}, args{name: "foobar"}, nil, true},
+ // Getting a connection when there are none should result in an error
+ {"none", fields{Connections: blank}, args{name: "foobar"}, nil, true},
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ r := &RemoteConfig{
+ Connections: tt.fields.Connections,
+ }
+ got, err := r.GetRemoteConnection(tt.args.name)
+ if (err != nil) != tt.wantErr {
+ t.Errorf("RemoteConfig.GetRemoteConnection() error = %v, wantErr %v", err, tt.wantErr)
+ return
+ }
+ if !reflect.DeepEqual(got, tt.want) {
+ t.Errorf("RemoteConfig.GetRemoteConnection() = %v, want %v", got, tt.want)
+ }
+ })
+ }
+}
diff --git a/cmd/podman/remoteclientconfig/errors.go b/cmd/podman/remoteclientconfig/errors.go
new file mode 100644
index 000000000..2689d3b49
--- /dev/null
+++ b/cmd/podman/remoteclientconfig/errors.go
@@ -0,0 +1,14 @@
+package remoteclientconfig
+
+import "errors"
+
+var (
+ // ErrNoDefaultConnection no default connection is defined in the podman-remote.conf file
+ ErrNoDefaultConnection = errors.New("no default connection is defined")
+ // ErrNoDefinedConnections no connections are defined in the podman-remote.conf file
+ ErrNoDefinedConnections = errors.New("no remote connections have been defined")
+ // ErrConnectionNotFound unable to lookup connection by name
+ ErrConnectionNotFound = errors.New("remote connection not found by name")
+ // ErrNoConfigationFile no config file found
+ ErrNoConfigationFile = errors.New("no configuration file found")
+)
diff --git a/cmd/podman/restart.go b/cmd/podman/restart.go
index 437676eef..494a9ec06 100644
--- a/cmd/podman/restart.go
+++ b/cmd/podman/restart.go
@@ -2,7 +2,7 @@ package main
import (
"github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/adapter"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -39,8 +39,8 @@ func init() {
flags.BoolVarP(&restartCommand.All, "all", "a", false, "Restart all non-running containers")
flags.BoolVarP(&restartCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
flags.BoolVar(&restartCommand.Running, "running", false, "Restart only running containers when --all is used")
- flags.UintVarP(&restartCommand.Timeout, "timeout", "t", libpod.CtrRemoveTimeout, "Seconds to wait for stop before killing the container")
- flags.UintVar(&restartCommand.Timeout, "time", libpod.CtrRemoveTimeout, "Seconds to wait for stop before killing the container")
+ flags.UintVarP(&restartCommand.Timeout, "timeout", "t", define.CtrRemoveTimeout, "Seconds to wait for stop before killing the container")
+ flags.UintVar(&restartCommand.Timeout, "time", define.CtrRemoveTimeout, "Seconds to wait for stop before killing the container")
markFlagHiddenForRemoteClient("latest", flags)
}
@@ -48,18 +48,18 @@ func init() {
func restartCmd(c *cliconfig.RestartValues) error {
all := c.All
if len(c.InputArgs) < 1 && !c.Latest && !all {
- return errors.Wrapf(libpod.ErrInvalidArg, "you must provide at least one container name or ID")
+ return errors.Wrapf(define.ErrInvalidArg, "you must provide at least one container name or ID")
}
runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
ok, failures, err := runtime.Restart(getContext(), c)
if err != nil {
- if errors.Cause(err) == libpod.ErrNoSuchCtr {
+ if errors.Cause(err) == define.ErrNoSuchCtr {
if len(c.InputArgs) > 1 {
exitCode = 125
} else {
diff --git a/cmd/podman/restore.go b/cmd/podman/restore.go
index 8cfd5ca0d..3ae141d41 100644
--- a/cmd/podman/restore.go
+++ b/cmd/podman/restore.go
@@ -2,7 +2,6 @@ package main
import (
"github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/adapter"
"github.com/containers/libpod/pkg/rootless"
"github.com/pkg/errors"
@@ -24,10 +23,10 @@ var (
restoreCommand.InputArgs = args
restoreCommand.GlobalFlags = MainGlobalOpts
restoreCommand.Remote = remoteclient
- return restoreCmd(&restoreCommand)
+ return restoreCmd(&restoreCommand, cmd)
},
Args: func(cmd *cobra.Command, args []string) error {
- return checkAllAndLatest(cmd, args, false)
+ return checkAllAndLatest(cmd, args, true)
},
Example: `podman container restore ctrID
podman container restore --latest
@@ -43,13 +42,15 @@ func init() {
flags.BoolVarP(&restoreCommand.All, "all", "a", false, "Restore all checkpointed containers")
flags.BoolVarP(&restoreCommand.Keep, "keep", "k", false, "Keep all temporary checkpoint files")
flags.BoolVarP(&restoreCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
- // TODO: add ContainerStateCheckpointed
- flags.BoolVar(&restoreCommand.TcpEstablished, "tcp-established", false, "Checkpoint a container with established TCP connections")
+ flags.BoolVar(&restoreCommand.TcpEstablished, "tcp-established", false, "Restore a container with established TCP connections")
+ flags.StringVarP(&restoreCommand.Import, "import", "i", "", "Restore from exported checkpoint archive (tar.gz)")
+ flags.StringVarP(&restoreCommand.Name, "name", "n", "", "Specify new name for container restored from exported checkpoint (only works with --import)")
+ flags.BoolVar(&restoreCommand.IgnoreRootfs, "ignore-rootfs", false, "Do not apply root file-system changes when importing from exported checkpoint")
markFlagHiddenForRemoteClient("latest", flags)
}
-func restoreCmd(c *cliconfig.RestoreValues) error {
+func restoreCmd(c *cliconfig.RestoreValues, cmd *cobra.Command) error {
if rootless.IsRootless() {
return errors.New("restoring a container requires root")
}
@@ -58,11 +59,36 @@ func restoreCmd(c *cliconfig.RestoreValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
- options := libpod.ContainerCheckpointOptions{
- Keep: c.Keep,
- TCPEstablished: c.TcpEstablished,
+ if c.Import == "" && c.IgnoreRootfs {
+ return errors.Errorf("--ignore-rootfs can only be used with --import")
}
- return runtime.Restore(c, options)
+
+ if c.Import == "" && c.Name != "" {
+ return errors.Errorf("--name can only be used with --import")
+ }
+
+ if c.Name != "" && c.TcpEstablished {
+ return errors.Errorf("--tcp-established cannot be used with --name")
+ }
+
+ argLen := len(c.InputArgs)
+ if c.Import != "" {
+ if c.All || c.Latest {
+ return errors.Errorf("Cannot use --import with --all or --latest")
+ }
+ if argLen > 0 {
+ return errors.Errorf("Cannot use --import with positional arguments")
+ }
+ }
+
+ if (c.All || c.Latest) && argLen > 0 {
+ return errors.Errorf("no arguments are needed with --all or --latest")
+ }
+ if argLen < 1 && !c.All && !c.Latest && c.Import == "" {
+ return errors.Errorf("you must provide at least one name or id")
+ }
+
+ return runtime.Restore(getContext(), c)
}
diff --git a/cmd/podman/rm.go b/cmd/podman/rm.go
index 1bf56b782..958ca1c60 100644
--- a/cmd/podman/rm.go
+++ b/cmd/podman/rm.go
@@ -4,7 +4,7 @@ import (
"fmt"
"github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/adapter"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -42,7 +42,9 @@ func init() {
flags.BoolVarP(&rmCommand.All, "all", "a", false, "Remove all containers")
flags.BoolVarP(&rmCommand.Force, "force", "f", false, "Force removal of a running container. The default is false")
flags.BoolVarP(&rmCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
+ flags.BoolVar(&rmCommand.Storage, "storage", false, "Remove container from storage library")
flags.BoolVarP(&rmCommand.Volumes, "volumes", "v", false, "Remove the volumes associated with the container")
+ markFlagHiddenForRemoteClient("storage", flags)
markFlagHiddenForRemoteClient("latest", flags)
}
@@ -52,11 +54,18 @@ func rmCmd(c *cliconfig.RmValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
+
+ // Storage conflicts with --all/--latest/--volumes
+ if c.Storage {
+ if c.All || c.Latest || c.Volumes {
+ return errors.Errorf("--storage conflicts with --volumes, --all, and --latest")
+ }
+ }
ok, failures, err := runtime.RemoveContainers(getContext(), c)
if err != nil {
- if errors.Cause(err) == libpod.ErrNoSuchCtr {
+ if errors.Cause(err) == define.ErrNoSuchCtr {
if len(c.InputArgs) > 1 {
exitCode = 125
} else {
diff --git a/cmd/podman/rmi.go b/cmd/podman/rmi.go
index 4c41a3ad5..57e78c34a 100644
--- a/cmd/podman/rmi.go
+++ b/cmd/podman/rmi.go
@@ -55,7 +55,7 @@ func rmiCmd(c *cliconfig.RmiValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
args := c.InputArgs
if len(args) == 0 && !removeAll {
@@ -87,7 +87,7 @@ func rmiCmd(c *cliconfig.RmiValues) error {
if removeAll {
var imagesToDelete []*adapter.ContainerImage
- imagesToDelete, err = runtime.GetImages()
+ imagesToDelete, err = runtime.GetRWImages()
if err != nil {
return errors.Wrapf(err, "unable to query local images")
}
@@ -107,7 +107,7 @@ func rmiCmd(c *cliconfig.RmiValues) error {
removeImage(i)
}
lastNumberofImages = len(imagesToDelete)
- imagesToDelete, err = runtime.GetImages()
+ imagesToDelete, err = runtime.GetRWImages()
if err != nil {
return err
}
diff --git a/cmd/podman/run.go b/cmd/podman/run.go
index 7d84d716b..4836c99dc 100644
--- a/cmd/podman/run.go
+++ b/cmd/podman/run.go
@@ -3,7 +3,7 @@ package main
import (
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/pkg/adapter"
- opentracing "github.com/opentracing/opentracing-go"
+ "github.com/opentracing/opentracing-go"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@@ -34,10 +34,10 @@ func init() {
runCommand.SetUsageTemplate(UsageTemplate())
flags := runCommand.Flags()
flags.SetInterspersed(false)
+ flags.SetNormalizeFunc(aliasFlags)
flags.Bool("sig-proxy", true, "Proxy received signals to the process")
getCreateFlags(&runCommand.PodmanCommand)
markFlagHiddenForRemoteClient("authfile", flags)
- flags.MarkHidden("signature-policy")
}
func runCmd(c *cliconfig.RunValues) error {
@@ -54,7 +54,7 @@ func runCmd(c *cliconfig.RunValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
exitCode, err = runtime.Run(getContext(), c, exitCode)
return err
diff --git a/cmd/podman/runlabel.go b/cmd/podman/runlabel.go
index 59cbc7aa4..db6d390d5 100644
--- a/cmd/podman/runlabel.go
+++ b/cmd/podman/runlabel.go
@@ -10,7 +10,7 @@ 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/define"
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/util"
"github.com/containers/libpod/utils"
@@ -53,23 +53,23 @@ func init() {
flags.StringVar(&runlabelCommand.Opt1, "opt1", "", "Optional parameter to pass for install")
flags.StringVar(&runlabelCommand.Opt2, "opt2", "", "Optional parameter to pass for install")
flags.StringVar(&runlabelCommand.Opt3, "opt3", "", "Optional parameter to pass for install")
- flags.MarkHidden("opt1")
- flags.MarkHidden("opt2")
- flags.MarkHidden("opt3")
-
+ markFlagHidden(flags, "opt1")
+ markFlagHidden(flags, "opt2")
+ markFlagHidden(flags, "opt3")
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")
// Disabled flags for the remote client
if !remote {
- flags.StringVar(&runlabelCommand.Authfile, "authfile", getAuthFile(""), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
+ flags.StringVar(&runlabelCommand.Authfile, "authfile", shared.GetAuthFile(""), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
flags.StringVar(&runlabelCommand.CertDir, "cert-dir", "", "`Pathname` of a directory containing TLS certificates and keys")
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")
- flags.MarkDeprecated("pull", "podman will pull if not found in local storage")
- flags.MarkHidden("signature-policy")
+ if err := flags.MarkDeprecated("pull", "podman will pull if not found in local storage"); err != nil {
+ logrus.Error("unable to mark pull flag deprecated")
+ }
+ markFlagHidden(flags, "signature-policy")
}
- markFlagHiddenForRemoteClient("authfile", flags)
}
// installCmd gets the data from the command line and calls installImage
@@ -95,7 +95,7 @@ func runlabelCmd(c *cliconfig.RunlabelValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
args := c.InputArgs
if len(args) < 2 {
@@ -169,7 +169,7 @@ func runlabelCmd(c *cliconfig.RunlabelValues) error {
name := cmd[i+1]
ctr, err := runtime.LookupContainer(name)
if err != nil {
- if errors.Cause(err) != libpod.ErrNoSuchCtr {
+ if errors.Cause(err) != define.ErrNoSuchCtr {
logrus.Debugf("Error occurred searching for container %s: %s", name, err.Error())
return err
}
diff --git a/cmd/podman/save.go b/cmd/podman/save.go
index 4d204337e..237ebde03 100644
--- a/cmd/podman/save.go
+++ b/cmd/podman/save.go
@@ -9,8 +9,8 @@ import (
"github.com/containers/libpod/pkg/adapter"
"github.com/containers/libpod/pkg/util"
"github.com/pkg/errors"
- "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
+ "golang.org/x/crypto/ssh/terminal"
)
const (
@@ -74,7 +74,7 @@ func saveCmd(c *cliconfig.SaveValues) error {
if err != nil {
return errors.Wrapf(err, "could not create runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
if c.Flag("compress").Changed && (c.Format != ociManifestDir && c.Format != v2s2ManifestDir && c.Format == "") {
return errors.Errorf("--compress can only be set when --format is either 'oci-dir' or 'docker-dir'")
@@ -82,7 +82,7 @@ func saveCmd(c *cliconfig.SaveValues) error {
if len(c.Output) == 0 {
fi := os.Stdout
- if logrus.IsTerminal(fi) {
+ if terminal.IsTerminal(int(fi.Fd())) {
return errors.Errorf("refusing to save to terminal. Use -o flag or redirect")
}
c.Output = "/dev/stdout"
diff --git a/cmd/podman/search.go b/cmd/podman/search.go
index ba04002f6..f4c51bff1 100644
--- a/cmd/podman/search.go
+++ b/cmd/podman/search.go
@@ -7,16 +7,12 @@ import (
"github.com/containers/buildah/pkg/formats"
"github.com/containers/image/types"
"github.com/containers/libpod/cmd/podman/cliconfig"
+ "github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod/image"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
-const (
- descriptionTruncLength = 44
- maxQueries = 25
-)
-
var (
searchCommand cliconfig.SearchValues
searchDescription = `Search registries for a given image. Can search all the default registries or a specific registry.
@@ -49,7 +45,7 @@ func init() {
flags.BoolVar(&searchCommand.NoTrunc, "no-trunc", false, "Do not truncate the output")
// Disabled flags for the remote client
if !remote {
- flags.StringVar(&searchCommand.Authfile, "authfile", getAuthFile(""), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
+ flags.StringVar(&searchCommand.Authfile, "authfile", shared.GetAuthFile(""), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
flags.BoolVar(&searchCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries")
}
}
@@ -88,8 +84,7 @@ func searchCmd(c *cliconfig.SearchValues) error {
return nil
}
out := formats.StdoutTemplateArray{Output: searchToGeneric(results), Template: format, Fields: searchHeaderMap()}
- formats.Writer(out).Out()
- return nil
+ return out.Out()
}
// searchHeaderMap returns the headers of a SearchResult.
diff --git a/cmd/podman/shared/container.go b/cmd/podman/shared/container.go
index 55cc529e0..7f53f5ec9 100644
--- a/cmd/podman/shared/container.go
+++ b/cmd/podman/shared/container.go
@@ -4,7 +4,6 @@ import (
"context"
"fmt"
"io"
- v1 "k8s.io/api/core/v1"
"os"
"path/filepath"
"regexp"
@@ -16,16 +15,15 @@ import (
"github.com/containers/image/types"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/libpod/image"
- "github.com/containers/libpod/pkg/inspect"
- cc "github.com/containers/libpod/pkg/spec"
"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"
+ v1 "k8s.io/api/core/v1"
)
const (
@@ -34,7 +32,7 @@ const (
cmdTruncLength = 17
)
-// PsOptions describes the struct being formed for ps
+// PsOptions describes the struct being formed for ps.
type PsOptions struct {
All bool
Format string
@@ -49,11 +47,11 @@ type PsOptions struct {
Sync bool
}
-// BatchContainerStruct is the return obkect from BatchContainer and contains
-// container related information
+// BatchContainerStruct is the return object from BatchContainer and contains
+// container related information.
type BatchContainerStruct struct {
ConConfig *libpod.ContainerConfig
- ConState libpod.ContainerStatus
+ ConState define.ContainerStatus
ExitCode int32
Exited bool
Pid int
@@ -63,7 +61,7 @@ type BatchContainerStruct struct {
}
// PsContainerOutput is the struct being returned from a parallel
-// Batch operation
+// batch operation.
type PsContainerOutput struct {
ID string
Image string
@@ -73,7 +71,7 @@ type PsContainerOutput struct {
Names string
IsInfra bool
Status string
- State libpod.ContainerStatus
+ State define.ContainerStatus
Pid int
Size *ContainerSize
Pod string
@@ -92,7 +90,7 @@ type PsContainerOutput struct {
Mounts string
}
-// Namespace describes output for ps namespace
+// Namespace describes output for ps namespace.
type Namespace struct {
PID string `json:"pid,omitempty"`
Cgroup string `json:"cgroup,omitempty"`
@@ -105,17 +103,17 @@ type Namespace struct {
}
// ContainerSize holds the size of the container's root filesystem and top
-// read-write layer
+// read-write layer.
type ContainerSize struct {
RootFsSize int64 `json:"rootFsSize"`
RwSize int64 `json:"rwSize"`
}
// NewBatchContainer runs a batch process under one lock to get container information and only
-// be called in PBatch
+// be called in PBatch.
func NewBatchContainer(ctr *libpod.Container, opts PsOptions) (PsContainerOutput, error) {
var (
- conState libpod.ContainerStatus
+ conState define.ContainerStatus
command string
created string
status string
@@ -186,16 +184,16 @@ func NewBatchContainer(ctr *libpod.Container, opts PsOptions) (PsContainerOutput
}
switch conState.String() {
- case libpod.ContainerStateExited.String():
+ case define.ContainerStateExited.String():
fallthrough
- case libpod.ContainerStateStopped.String():
+ case define.ContainerStateStopped.String():
exitedSince := units.HumanDuration(time.Since(exitedAt))
status = fmt.Sprintf("Exited (%d) %s ago", exitCode, exitedSince)
- case libpod.ContainerStateRunning.String():
+ case define.ContainerStateRunning.String():
status = "Up " + units.HumanDuration(time.Since(startedAt)) + " ago"
- case libpod.ContainerStatePaused.String():
+ case define.ContainerStatePaused.String():
status = "Paused"
- case libpod.ContainerStateCreated.String(), libpod.ContainerStateConfigured.String():
+ case define.ContainerStateCreated.String(), define.ContainerStateConfigured.String():
status = "Created"
default:
status = "Error"
@@ -259,15 +257,15 @@ type workerInput struct {
job int
}
-// worker is a "threaded" worker that takes jobs from the channel "queue"
+// worker is a "threaded" worker that takes jobs from the channel "queue".
func worker(wg *sync.WaitGroup, jobs <-chan workerInput, results chan<- PsContainerOutput, errors chan<- error) {
for j := range jobs {
r, err := j.parallelFunc()
- // If we find an error, we return just the error
+ // If we find an error, we return just the error.
if err != nil {
errors <- err
} else {
- // Return the result
+ // Return the result.
results <- r
}
wg.Done()
@@ -281,8 +279,8 @@ func generateContainerFilterFuncs(filter, filterValue string, r *libpod.Runtime)
return strings.Contains(c.ID(), filterValue)
}, nil
case "label":
- var filterArray []string = strings.SplitN(filterValue, "=", 2)
- var filterKey string = filterArray[0]
+ var filterArray = strings.SplitN(filterValue, "=", 2)
+ var filterKey = filterArray[0]
if len(filterArray) > 1 {
filterValue = filterArray[1]
} else {
@@ -298,7 +296,11 @@ func generateContainerFilterFuncs(filter, filterValue string, r *libpod.Runtime)
}, nil
case "name":
return func(c *libpod.Container) bool {
- return strings.Contains(c.Name(), filterValue)
+ match, err := regexp.MatchString(filterValue, c.Name())
+ if err != nil {
+ return false
+ }
+ return match
}, nil
case "exited":
exitCode, err := strconv.ParseInt(filterValue, 10, 32)
@@ -307,7 +309,7 @@ func generateContainerFilterFuncs(filter, filterValue string, r *libpod.Runtime)
}
return func(c *libpod.Container) bool {
ec, exited, err := c.ExitCode()
- if ec == int32(exitCode) && err == nil && exited == true {
+ if ec == int32(exitCode) && err == nil && exited {
return true
}
return false
@@ -325,9 +327,9 @@ func generateContainerFilterFuncs(filter, filterValue string, r *libpod.Runtime)
filterValue = "exited"
}
state := status.String()
- if status == libpod.ContainerStateConfigured {
+ if status == define.ContainerStateConfigured {
state = "created"
- } else if status == libpod.ContainerStateStopped {
+ } else if status == define.ContainerStateStopped {
state = "exited"
}
return state == filterValue
@@ -396,7 +398,7 @@ func generateContainerFilterFuncs(filter, filterValue string, r *libpod.Runtime)
return nil, errors.Errorf("%s is an invalid filter", filter)
}
-// GetPsContainerOutput returns a slice of containers specifically for ps output
+// GetPsContainerOutput returns a slice of containers specifically for ps output.
func GetPsContainerOutput(r *libpod.Runtime, opts PsOptions, filters []string, maxWorkers int) ([]PsContainerOutput, error) {
var (
filterFuncs []libpod.ContainerFilter
@@ -417,21 +419,21 @@ func GetPsContainerOutput(r *libpod.Runtime, opts PsOptions, filters []string, m
}
}
if !opts.Latest {
- // Get all containers
+ // Get all containers.
containers, err := r.GetContainers(filterFuncs...)
if err != nil {
return nil, err
}
- // We only want the last few containers
+ // We only want the last few containers.
if opts.Last > 0 && opts.Last <= len(containers) {
return nil, errors.Errorf("--last not yet supported")
} else {
outputContainers = containers
}
} else {
- // Get just the latest container
- // Ignore filters
+ // Get just the latest container.
+ // Ignore filters.
latestCtr, err := r.GetLatestContainer()
if err != nil {
return nil, err
@@ -444,8 +446,8 @@ func GetPsContainerOutput(r *libpod.Runtime, opts PsOptions, filters []string, m
return pss, nil
}
-// PBatch is performs batch operations on a container in parallel. It spawns the number of workers
-// relative to the the number of parallel operations desired.
+// PBatch performs batch operations on a container in parallel. It spawns the
+// number of workers relative to the number of parallel operations desired.
func PBatch(containers []*libpod.Container, workers int, opts PsOptions) []PsContainerOutput {
var (
wg sync.WaitGroup
@@ -453,7 +455,7 @@ func PBatch(containers []*libpod.Container, workers int, opts PsOptions) []PsCon
)
// If the number of containers in question is less than the number of
- // proposed parallel operations, we shouldnt spawn so many workers
+ // proposed parallel operations, we shouldnt spawn so many workers.
if workers > len(containers) {
workers = len(containers)
}
@@ -462,12 +464,12 @@ func PBatch(containers []*libpod.Container, workers int, opts PsOptions) []PsCon
results := make(chan PsContainerOutput, len(containers))
batchErrors := make(chan error, len(containers))
- // Create the workers
+ // Create the workers.
for w := 1; w <= workers; w++ {
go worker(&wg, jobs, results, batchErrors)
}
- // Add jobs to the workers
+ // Add jobs to the workers.
for i, j := range containers {
j := j
wg.Add(1)
@@ -492,7 +494,7 @@ func PBatch(containers []*libpod.Container, workers int, opts PsOptions) []PsCon
// We sort out running vs non-running here to save lots of copying
// later.
if !opts.All && !opts.Latest && opts.Last < 1 {
- if !res.IsInfra && res.State == libpod.ContainerStateRunning {
+ if !res.IsInfra && res.State == define.ContainerStateRunning {
psResults = append(psResults, res)
}
} else {
@@ -502,12 +504,12 @@ func PBatch(containers []*libpod.Container, workers int, opts PsOptions) []PsCon
return psResults
}
-// BatchContainer is used in ps to reduce performance hits by "batching"
+// BatchContainerOp is used in ps to reduce performance hits by "batching"
// locks.
func BatchContainerOp(ctr *libpod.Container, opts PsOptions) (BatchContainerStruct, error) {
var (
conConfig *libpod.ContainerConfig
- conState libpod.ContainerStatus
+ conState define.ContainerStatus
err error
exitCode int32
exited bool
@@ -580,7 +582,7 @@ func BatchContainerOp(ctr *libpod.Container, opts PsOptions) (BatchContainerStru
}, nil
}
-// GetNamespaces returns a populated namespace struct
+// GetNamespaces returns a populated namespace struct.
func GetNamespaces(pid int) *Namespace {
ctrPID := strconv.Itoa(pid)
cgroup, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "cgroup"))
@@ -611,9 +613,9 @@ func getNamespaceInfo(path string) (string, error) {
return getStrFromSquareBrackets(val), nil
}
-// getStrFromSquareBrackets gets the string inside [] from a string
+// getStrFromSquareBrackets gets the string inside [] from a string.
func getStrFromSquareBrackets(cmd string) string {
- reg, err := regexp.Compile(".*\\[|\\].*")
+ reg, err := regexp.Compile(`.*\[|\].*`)
if err != nil {
return ""
}
@@ -621,145 +623,6 @@ func getStrFromSquareBrackets(cmd string) string {
return strings.Join(arr, ",")
}
-// GetCtrInspectInfo takes container inspect data and collects all its info into a ContainerData
-// structure for inspection related methods
-func GetCtrInspectInfo(config *libpod.ContainerConfig, ctrInspectData *inspect.ContainerInspectData, createArtifact *cc.CreateConfig) (*inspect.ContainerData, error) {
- spec := config.Spec
-
- cpus, mems, period, quota, realtimePeriod, realtimeRuntime, shares := getCPUInfo(spec)
- blkioWeight, blkioWeightDevice, blkioReadBps, blkioWriteBps, blkioReadIOPS, blkioeWriteIOPS := getBLKIOInfo(spec)
- memKernel, memReservation, memSwap, memSwappiness, memDisableOOMKiller := getMemoryInfo(spec)
- pidsLimit := getPidsInfo(spec)
- cgroup := getCgroup(spec)
- logConfig := inspect.LogConfig{
- config.LogDriver,
- make(map[string]string),
- }
-
- data := &inspect.ContainerData{
- ctrInspectData,
- &inspect.HostConfig{
- ConsoleSize: spec.Process.ConsoleSize,
- OomScoreAdj: spec.Process.OOMScoreAdj,
- CPUShares: shares,
- BlkioWeight: blkioWeight,
- BlkioWeightDevice: blkioWeightDevice,
- BlkioDeviceReadBps: blkioReadBps,
- BlkioDeviceWriteBps: blkioWriteBps,
- BlkioDeviceReadIOps: blkioReadIOPS,
- BlkioDeviceWriteIOps: blkioeWriteIOPS,
- CPUPeriod: period,
- CPUQuota: quota,
- CPURealtimePeriod: realtimePeriod,
- CPURealtimeRuntime: realtimeRuntime,
- CPUSetCPUs: cpus,
- CPUSetMems: mems,
- Devices: spec.Linux.Devices,
- KernelMemory: memKernel,
- MemoryReservation: memReservation,
- MemorySwap: memSwap,
- MemorySwappiness: memSwappiness,
- OomKillDisable: memDisableOOMKiller,
- PidsLimit: pidsLimit,
- Privileged: config.Privileged,
- ReadOnlyRootfs: spec.Root.Readonly,
- ReadOnlyTmpfs: createArtifact.ReadOnlyTmpfs,
- Runtime: config.OCIRuntime,
- NetworkMode: string(createArtifact.NetMode),
- IpcMode: string(createArtifact.IpcMode),
- Cgroup: cgroup,
- UTSMode: string(createArtifact.UtsMode),
- UsernsMode: string(createArtifact.UsernsMode),
- GroupAdd: spec.Process.User.AdditionalGids,
- ContainerIDFile: createArtifact.CidFile,
- AutoRemove: createArtifact.Rm,
- CapAdd: createArtifact.CapAdd,
- CapDrop: createArtifact.CapDrop,
- DNS: createArtifact.DNSServers,
- DNSOptions: createArtifact.DNSOpt,
- DNSSearch: createArtifact.DNSSearch,
- PidMode: string(createArtifact.PidMode),
- CgroupParent: createArtifact.CgroupParent,
- ShmSize: createArtifact.Resources.ShmSize,
- Memory: createArtifact.Resources.Memory,
- Ulimits: createArtifact.Resources.Ulimit,
- SecurityOpt: createArtifact.SecurityOpts,
- Tmpfs: createArtifact.Tmpfs,
- LogConfig: &logConfig,
- },
- &inspect.CtrConfig{
- Hostname: spec.Hostname,
- User: spec.Process.User,
- Env: spec.Process.Env,
- Image: config.RootfsImageName,
- WorkingDir: spec.Process.Cwd,
- Labels: config.Labels,
- Annotations: spec.Annotations,
- Tty: spec.Process.Terminal,
- OpenStdin: config.Stdin,
- StopSignal: config.StopSignal,
- Cmd: config.Spec.Process.Args,
- Entrypoint: strings.Join(createArtifact.Entrypoint, " "),
- Healthcheck: config.HealthCheckConfig,
- },
- }
- return data, nil
-}
-
-func getCPUInfo(spec *specs.Spec) (string, string, *uint64, *int64, *uint64, *int64, *uint64) {
- if spec.Linux.Resources == nil {
- return "", "", nil, nil, nil, nil, nil
- }
- cpu := spec.Linux.Resources.CPU
- if cpu == nil {
- return "", "", nil, nil, nil, nil, nil
- }
- return cpu.Cpus, cpu.Mems, cpu.Period, cpu.Quota, cpu.RealtimePeriod, cpu.RealtimeRuntime, cpu.Shares
-}
-
-func getBLKIOInfo(spec *specs.Spec) (*uint16, []specs.LinuxWeightDevice, []specs.LinuxThrottleDevice, []specs.LinuxThrottleDevice, []specs.LinuxThrottleDevice, []specs.LinuxThrottleDevice) {
- if spec.Linux.Resources == nil {
- return nil, nil, nil, nil, nil, nil
- }
- blkio := spec.Linux.Resources.BlockIO
- if blkio == nil {
- return nil, nil, nil, nil, nil, nil
- }
- return blkio.Weight, blkio.WeightDevice, blkio.ThrottleReadBpsDevice, blkio.ThrottleWriteBpsDevice, blkio.ThrottleReadIOPSDevice, blkio.ThrottleWriteIOPSDevice
-}
-
-func getMemoryInfo(spec *specs.Spec) (*int64, *int64, *int64, *uint64, *bool) {
- if spec.Linux.Resources == nil {
- return nil, nil, nil, nil, nil
- }
- memory := spec.Linux.Resources.Memory
- if memory == nil {
- return nil, nil, nil, nil, nil
- }
- return memory.Kernel, memory.Reservation, memory.Swap, memory.Swappiness, memory.DisableOOMKiller
-}
-
-func getPidsInfo(spec *specs.Spec) *int64 {
- if spec.Linux.Resources == nil {
- return nil
- }
- pids := spec.Linux.Resources.Pids
- if pids == nil {
- return nil
- }
- return &pids.Limit
-}
-
-func getCgroup(spec *specs.Spec) string {
- cgroup := "host"
- for _, ns := range spec.Linux.Namespaces {
- if ns.Type == specs.CgroupNamespace && ns.Path != "" {
- cgroup = "container"
- }
- }
- return cgroup
-}
-
func comparePorts(i, j ocicni.PortMapping) bool {
if i.ContainerPort != j.ContainerPort {
return i.ContainerPort < j.ContainerPort
@@ -776,8 +639,8 @@ func comparePorts(i, j ocicni.PortMapping) bool {
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
+// formatGroup 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]
@@ -797,7 +660,7 @@ func formatGroup(key string, start, last int32) string {
}
// portsToString converts the ports used to a string of the from "port1, port2"
-// also groups continuous list of ports in readable format.
+// and also groups continuous list of ports in readable format.
func portsToString(ports []ocicni.PortMapping) string {
type portGroup struct {
first int32
@@ -812,7 +675,7 @@ func portsToString(ports []ocicni.PortMapping) string {
return comparePorts(ports[i], ports[j])
})
- // portGroupMap is used for grouping continuous ports
+ // portGroupMap is used for grouping continuous ports.
portGroupMap := make(map[string]*portGroup)
var groupKeyList []string
@@ -822,7 +685,7 @@ func portsToString(ports []ocicni.PortMapping) string {
if hostIP == "" {
hostIP = "0.0.0.0"
}
- // if hostPort and containerPort are not same, consider as individual port.
+ // 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
@@ -833,7 +696,7 @@ func portsToString(ports []ocicni.PortMapping) string {
portgroup, ok := portGroupMap[portMapKey]
if !ok {
portGroupMap[portMapKey] = &portGroup{first: v.ContainerPort, last: v.ContainerPort}
- // this list is required to travese portGroupMap
+ // This list is required to travese portGroupMap.
groupKeyList = append(groupKeyList, portMapKey)
continue
}
@@ -843,7 +706,7 @@ func portsToString(ports []ocicni.PortMapping) string {
continue
}
}
- // for each portMapKey, format group list and appned to output string
+ // 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))
@@ -852,7 +715,7 @@ func portsToString(ports []ocicni.PortMapping) string {
}
// GetRunlabel is a helper function for runlabel; it gets the image if needed and begins the
-// contruction of the runlabel output and environment variables
+// construction of the runlabel output and environment variables.
func GetRunlabel(label string, runlabelImage string, ctx context.Context, runtime *libpod.Runtime, pull bool, inputCreds string, dockerRegistryOptions image.DockerRegistryOptions, authfile string, signaturePolicyPath string, output io.Writer) (string, string, error) {
var (
newImage *image.Image
@@ -887,9 +750,9 @@ func GetRunlabel(label string, runlabelImage string, ctx context.Context, runtim
return runLabel, imageName, err
}
-// GenerateRunlabelCommand generates the command that will eventually be execucted by podman
+// GenerateRunlabelCommand generates the command that will eventually be execucted by podman.
func GenerateRunlabelCommand(runLabel, imageName, name string, opts map[string]string, extraArgs []string, globalOpts string) ([]string, []string, error) {
- // If no name is provided, we use the image's basename instead
+ // If no name is provided, we use the image's basename instead.
if name == "" {
baseName, err := image.GetImageBaseName(imageName)
if err != nil {
@@ -897,7 +760,7 @@ func GenerateRunlabelCommand(runLabel, imageName, name string, opts map[string]s
}
name = baseName
}
- // The user provided extra arguments that need to be tacked onto the label's command
+ // The user provided extra arguments that need to be tacked onto the label's command.
if len(extraArgs) > 0 {
runLabel = fmt.Sprintf("%s %s", runLabel, strings.Join(extraArgs, " "))
}
@@ -919,7 +782,7 @@ func GenerateRunlabelCommand(runLabel, imageName, name string, opts map[string]s
case "OPT3":
return envmap["OPT3"]
case "PWD":
- // I would prefer to use os.getenv but it appears PWD is not in the os env list
+ // I would prefer to use os.getenv but it appears PWD is not in the os env list.
d, err := os.Getwd()
if err != nil {
logrus.Error("unable to determine current working directory")
@@ -956,7 +819,7 @@ func GenerateKube(name string, service bool, r *libpod.Runtime) (*v1.Pod, *v1.Se
servicePorts []v1.ServicePort
serviceYAML v1.Service
)
- // Get the container in question
+ // Get the container in question.
container, err = r.LookupContainer(name)
if err != nil {
pod, err = r.LookupPod(name)
@@ -966,7 +829,7 @@ func GenerateKube(name string, service bool, r *libpod.Runtime) (*v1.Pod, *v1.Se
podYAML, servicePorts, err = pod.GenerateForKube()
} else {
if len(container.Dependencies()) > 0 {
- return nil, nil, errors.Wrapf(libpod.ErrNotImplemented, "containers with dependencies")
+ return nil, nil, errors.Wrapf(define.ErrNotImplemented, "containers with dependencies")
}
podYAML, err = container.GenerateForKube()
}
diff --git a/cmd/podman/shared/create.go b/cmd/podman/shared/create.go
index 7cf230605..9578eb17d 100644
--- a/cmd/podman/shared/create.go
+++ b/cmd/podman/shared/create.go
@@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"fmt"
+ "github.com/containers/libpod/pkg/errorhandling"
"io"
"os"
"path/filepath"
@@ -25,7 +26,6 @@ import (
"github.com/docker/docker/pkg/signal"
"github.com/docker/go-connections/nat"
"github.com/docker/go-units"
- "github.com/google/shlex"
"github.com/opencontainers/selinux/go-selinux/label"
"github.com/opentracing/opentracing-go"
"github.com/pkg/errors"
@@ -56,15 +56,15 @@ func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod.
}
if c.IsSet("cidfile") && os.Geteuid() == 0 {
- cidFile, err = libpod.OpenExclusiveFile(c.String("cidfile"))
+ cidFile, err = util.OpenExclusiveFile(c.String("cidfile"))
if err != nil && os.IsExist(err) {
return nil, nil, errors.Errorf("container id file exists. Ensure another container is not using it or delete %s", c.String("cidfile"))
}
if err != nil {
return nil, nil, errors.Errorf("error opening cidfile %s", c.String("cidfile"))
}
- defer cidFile.Close()
- defer cidFile.Sync()
+ defer errorhandling.CloseQuiet(cidFile)
+ defer errorhandling.SyncQuiet(cidFile)
}
imageName := ""
@@ -77,11 +77,14 @@ func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod.
writer = os.Stderr
}
- newImage, err := runtime.ImageRuntime().New(ctx, c.InputArgs[0], rtc.SignaturePolicyPath, "", writer, nil, image.SigningOptions{}, false, nil)
+ newImage, err := runtime.ImageRuntime().New(ctx, c.InputArgs[0], rtc.SignaturePolicyPath, GetAuthFile(""), writer, nil, image.SigningOptions{}, false, nil)
if err != nil {
return nil, nil, err
}
data, err = newImage.Inspect(ctx)
+ if err != nil {
+ return nil, nil, err
+ }
names := newImage.Names()
if len(names) > 0 {
imageName = names[0]
@@ -89,9 +92,8 @@ func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod.
imageName = newImage.ID()
}
- var healthCheckCommandInput string
// if the user disabled the healthcheck with "none", we skip adding it
- healthCheckCommandInput = c.String("healthcheck-command")
+ healthCheckCommandInput := c.String("healthcheck-command")
// the user didnt disable the healthcheck but did pass in a healthcheck command
// now we need to make a healthcheck from the commandline input
@@ -113,6 +115,30 @@ func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod.
if err != nil {
return nil, nil, errors.Wrapf(err, "unable to get healthcheck for %s", c.InputArgs[0])
}
+
+ if healthCheck != nil {
+ hcCommand := healthCheck.Test
+ if len(hcCommand) < 1 || hcCommand[0] == "" || hcCommand[0] == "NONE" {
+ // disable health check
+ healthCheck = nil
+ } else {
+ // apply defaults if image doesn't override them
+ if healthCheck.Interval == 0 {
+ healthCheck.Interval = 30 * time.Second
+ }
+ if healthCheck.Timeout == 0 {
+ healthCheck.Timeout = 30 * time.Second
+ }
+ /* Docker default is 0s, so the following would be a no-op
+ if healthCheck.StartPeriod == 0 {
+ healthCheck.StartPeriod = 0 * time.Second
+ }
+ */
+ if healthCheck.Retries == 0 {
+ healthCheck.Retries = 3
+ }
+ }
+ }
}
}
}
@@ -191,7 +217,7 @@ func parseSecurityOpt(config *cc.CreateConfig, securityOpts []string, runtime *l
} else {
con := strings.SplitN(opt, "=", 2)
if len(con) != 2 {
- return fmt.Errorf("Invalid --security-opt 1: %q", opt)
+ return fmt.Errorf("invalid --security-opt 1: %q", opt)
}
switch con[0] {
@@ -202,7 +228,7 @@ func parseSecurityOpt(config *cc.CreateConfig, securityOpts []string, runtime *l
case "seccomp":
config.SeccompProfilePath = con[1]
default:
- return fmt.Errorf("Invalid --security-opt 2: %q", opt)
+ return fmt.Errorf("invalid --security-opt 2: %q", opt)
}
}
}
@@ -256,13 +282,26 @@ func configurePod(c *GenericCLIResults, runtime *libpod.Runtime, namespaces map[
if err != nil {
return namespaces, err
}
+ hasUserns := false
+ if podInfraID != "" {
+ podCtr, err := runtime.GetContainer(podInfraID)
+ if err != nil {
+ return namespaces, err
+ }
+ mappings, err := podCtr.IDMappings()
+ if err != nil {
+ return namespaces, err
+ }
+ hasUserns = len(mappings.UIDMap) > 0
+ }
+
if (namespaces["pid"] == cc.Pod) || (!c.IsSet("pid") && pod.SharesPID()) {
namespaces["pid"] = fmt.Sprintf("container:%s", podInfraID)
}
if (namespaces["net"] == cc.Pod) || (!c.IsSet("net") && !c.IsSet("network") && pod.SharesNet()) {
namespaces["net"] = fmt.Sprintf("container:%s", podInfraID)
}
- if (namespaces["user"] == cc.Pod) || (!c.IsSet("user") && pod.SharesUser()) {
+ if hasUserns && (namespaces["user"] == cc.Pod) || (!c.IsSet("user") && pod.SharesUser()) {
namespaces["user"] = fmt.Sprintf("container:%s", podInfraID)
}
if (namespaces["ipc"] == cc.Pod) || (!c.IsSet("ipc") && pod.SharesIPC()) {
@@ -374,11 +413,12 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
namespaceNet = c.String("net")
}
namespaces = map[string]string{
- "pid": c.String("pid"),
- "net": namespaceNet,
- "ipc": c.String("ipc"),
- "user": c.String("userns"),
- "uts": c.String("uts"),
+ "cgroup": c.String("cgroupns"),
+ "pid": c.String("pid"),
+ "net": namespaceNet,
+ "ipc": c.String("ipc"),
+ "user": c.String("userns"),
+ "uts": c.String("uts"),
}
originalPodName := c.String("pod")
@@ -436,6 +476,11 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
return nil, errors.Errorf("--uts %q is not valid", namespaces["uts"])
}
+ cgroupMode := ns.CgroupMode(namespaces["cgroup"])
+ if !cgroupMode.Valid() {
+ return nil, errors.Errorf("--cgroup %q is not valid", namespaces["cgroup"])
+ }
+
ipcMode := ns.IpcMode(namespaces["ipc"])
if !cc.Valid(string(ipcMode), ipcMode) {
return nil, errors.Errorf("--ipc %q is not valid", ipcMode)
@@ -479,6 +524,16 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
// ENVIRONMENT VARIABLES
env := EnvVariablesFromData(data)
+ if c.Bool("env-host") {
+ for _, e := range os.Environ() {
+ pair := strings.SplitN(e, "=", 2)
+ if _, ok := env[pair[0]]; !ok {
+ if len(pair) > 1 {
+ env[pair[0]] = pair[1]
+ }
+ }
+ }
+ }
if err := parse.ReadKVStrings(env, c.StringSlice("env-file"), c.StringArray("env")); err != nil {
return nil, errors.Wrapf(err, "unable to process environment variables")
}
@@ -615,6 +670,8 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
ImageVolumeType: c.String("image-volume"),
CapAdd: c.StringSlice("cap-add"),
CapDrop: c.StringSlice("cap-drop"),
+ CidFile: c.String("cidfile"),
+ Cgroupns: c.String("cgroupns"),
CgroupParent: c.String("cgroup-parent"),
Command: command,
Detach: c.Bool("detach"),
@@ -650,6 +707,7 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
NetMode: netMode,
UtsMode: utsMode,
PidMode: pidMode,
+ CgroupMode: cgroupMode,
Pod: podName,
Privileged: c.Bool("privileged"),
Publish: c.StringSlice("publish"),
@@ -690,7 +748,7 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
StopTimeout: c.Uint("stop-timeout"),
Sysctl: sysctl,
Systemd: systemd,
- Tmpfs: c.StringSlice("tmpfs"),
+ Tmpfs: c.StringArray("tmpfs"),
Tty: tty,
User: user,
UsernsMode: usernsMode,
@@ -730,14 +788,6 @@ func CreateContainerFromCreateConfig(r *libpod.Runtime, createConfig *cc.CreateC
if err != nil {
return nil, err
}
-
- createConfigJSON, err := json.Marshal(createConfig)
- if err != nil {
- return nil, err
- }
- if err := ctr.AddArtifact("create-config", createConfigJSON); err != nil {
- return nil, err
- }
return ctr, nil
}
@@ -775,9 +825,12 @@ func makeHealthCheckFromCli(c *GenericCLIResults) (*manifest.Schema2HealthConfig
return nil, errors.New("Must define a healthcheck command for all healthchecks")
}
- cmd, err := shlex.Split(inCommand)
+ // first try to parse option value as JSON array of strings...
+ cmd := []string{}
+ err := json.Unmarshal([]byte(inCommand), &cmd)
if err != nil {
- return nil, errors.Wrap(err, "failed to parse healthcheck command")
+ // ...otherwise pass it to "/bin/sh -c" inside the container
+ cmd = []string{"CMD-SHELL", inCommand}
}
hc := manifest.Schema2HealthConfig{
Test: cmd,
@@ -801,7 +854,7 @@ func makeHealthCheckFromCli(c *GenericCLIResults) (*manifest.Schema2HealthConfig
if err != nil {
return nil, errors.Wrapf(err, "invalid healthcheck-timeout %s", inTimeout)
}
- if timeoutDuration < time.Duration(time.Second*1) {
+ if timeoutDuration < time.Duration(1) {
return nil, errors.New("healthcheck-timeout must be at least 1 second")
}
hc.Timeout = timeoutDuration
@@ -811,7 +864,7 @@ func makeHealthCheckFromCli(c *GenericCLIResults) (*manifest.Schema2HealthConfig
return nil, errors.Wrapf(err, "invalid healthcheck-start-period %s", inStartPeriod)
}
if startPeriodDuration < time.Duration(0) {
- return nil, errors.New("healthcheck-start-period must be a 0 seconds or greater")
+ return nil, errors.New("healthcheck-start-period must be 0 seconds or greater")
}
hc.StartPeriod = startPeriodDuration
diff --git a/cmd/podman/shared/create_cli.go b/cmd/podman/shared/create_cli.go
index 7f158b09a..08a40b206 100644
--- a/cmd/podman/shared/create_cli.go
+++ b/cmd/podman/shared/create_cli.go
@@ -5,9 +5,9 @@ import (
"strings"
"github.com/containers/libpod/cmd/podman/shared/parse"
+ "github.com/containers/libpod/pkg/cgroups"
cc "github.com/containers/libpod/pkg/spec"
"github.com/containers/libpod/pkg/sysinfo"
- "github.com/containers/libpod/pkg/util"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -78,7 +78,7 @@ func addWarning(warnings []string, msg string) []string {
func verifyContainerResources(config *cc.CreateConfig, update bool) ([]string, error) {
warnings := []string{}
- cgroup2, err := util.IsCgroup2UnifiedMode()
+ cgroup2, err := cgroups.IsCgroup2UnifiedMode()
if err != nil || cgroup2 {
return warnings, err
}
@@ -133,7 +133,7 @@ func verifyContainerResources(config *cc.CreateConfig, update bool) ([]string, e
if config.Resources.KernelMemory > 0 && config.Resources.KernelMemory < linuxMinMemory {
return warnings, fmt.Errorf("minimum kernel memory limit allowed is 4MB")
}
- if config.Resources.DisableOomKiller == true && !sysInfo.OomKillDisable {
+ if config.Resources.DisableOomKiller && !sysInfo.OomKillDisable {
// only produce warnings if the setting wasn't to *disable* the OOM Kill; no point
// warning the caller if they already wanted the feature to be off
warnings = addWarning(warnings, "Your kernel does not support OomKillDisable. OomKillDisable discarded.")
diff --git a/cmd/podman/shared/funcs.go b/cmd/podman/shared/funcs.go
index c189cceeb..2ceb9cdcb 100644
--- a/cmd/podman/shared/funcs.go
+++ b/cmd/podman/shared/funcs.go
@@ -9,6 +9,21 @@ import (
"github.com/google/shlex"
)
+func GetAuthFile(authfile string) string {
+ if authfile != "" {
+ return authfile
+ }
+ authfile = os.Getenv("REGISTRY_AUTH_FILE")
+ if authfile != "" {
+ return authfile
+ }
+ runtimeDir := os.Getenv("XDG_RUNTIME_DIR")
+ if runtimeDir != "" {
+ return filepath.Join(runtimeDir, "containers/auth.json")
+ }
+ return ""
+}
+
func substituteCommand(cmd string) (string, error) {
var (
newCommand string
diff --git a/cmd/podman/shared/intermediate.go b/cmd/podman/shared/intermediate.go
index a38e4d47a..4062ac48a 100644
--- a/cmd/podman/shared/intermediate.go
+++ b/cmd/podman/shared/intermediate.go
@@ -370,6 +370,7 @@ func NewIntermediateLayer(c *cliconfig.PodmanCommand, remote bool) GenericCLIRes
m["blkio-weight-device"] = newCRStringSlice(c, "blkio-weight-device")
m["cap-add"] = newCRStringSlice(c, "cap-add")
m["cap-drop"] = newCRStringSlice(c, "cap-drop")
+ m["cgroupns"] = newCRString(c, "cgroupns")
m["cgroup-parent"] = newCRString(c, "cgroup-parent")
m["cidfile"] = newCRString(c, "cidfile")
m["conmon-pidfile"] = newCRString(c, "conmon-pidfile")
@@ -393,16 +394,17 @@ func NewIntermediateLayer(c *cliconfig.PodmanCommand, remote bool) GenericCLIRes
m["dns-search"] = newCRStringSlice(c, "dns-search")
m["entrypoint"] = newCRString(c, "entrypoint")
m["env"] = newCRStringArray(c, "env")
+ m["env-host"] = newCRBool(c, "env-host")
m["env-file"] = newCRStringSlice(c, "env-file")
m["expose"] = newCRStringSlice(c, "expose")
m["gidmap"] = newCRStringSlice(c, "gidmap")
m["group-add"] = newCRStringSlice(c, "group-add")
m["help"] = newCRBool(c, "help")
- m["healthcheck-command"] = newCRString(c, "healthcheck-command")
- m["healthcheck-interval"] = newCRString(c, "healthcheck-interval")
- m["healthcheck-retries"] = newCRUint(c, "healthcheck-retries")
- m["healthcheck-start-period"] = newCRString(c, "healthcheck-start-period")
- m["healthcheck-timeout"] = newCRString(c, "healthcheck-timeout")
+ m["healthcheck-command"] = newCRString(c, "health-cmd")
+ m["healthcheck-interval"] = newCRString(c, "health-interval")
+ m["healthcheck-retries"] = newCRUint(c, "health-retries")
+ m["healthcheck-start-period"] = newCRString(c, "health-start-period")
+ m["healthcheck-timeout"] = newCRString(c, "health-timeout")
m["hostname"] = newCRString(c, "hostname")
m["http-proxy"] = newCRBool(c, "http-proxy")
m["image-volume"] = newCRString(c, "image-volume")
@@ -448,7 +450,7 @@ func NewIntermediateLayer(c *cliconfig.PodmanCommand, remote bool) GenericCLIRes
m["subuidname"] = newCRString(c, "subuidname")
m["sysctl"] = newCRStringSlice(c, "sysctl")
m["systemd"] = newCRBool(c, "systemd")
- m["tmpfs"] = newCRStringSlice(c, "tmpfs")
+ m["tmpfs"] = newCRStringArray(c, "tmpfs")
m["tty"] = newCRBool(c, "tty")
m["uidmap"] = newCRStringSlice(c, "uidmap")
m["ulimit"] = newCRStringSlice(c, "ulimit")
diff --git a/cmd/podman/shared/parse/parse.go b/cmd/podman/shared/parse/parse.go
index 7bc2652cb..9fbc92fc3 100644
--- a/cmd/podman/shared/parse/parse.go
+++ b/cmd/podman/shared/parse/parse.go
@@ -7,6 +7,7 @@ import (
"bufio"
"fmt"
"net"
+ "net/url"
"os"
"regexp"
"strings"
@@ -112,9 +113,22 @@ func parseEnv(env map[string]string, line string) error {
if len(data) > 1 {
env[name] = data[1]
} else {
- // if only a pass-through variable is given, clean it up.
- val, _ := os.LookupEnv(name)
- env[name] = val
+ if strings.HasSuffix(name, "*") {
+ name = strings.TrimSuffix(name, "*")
+ for _, e := range os.Environ() {
+ part := strings.SplitN(e, "=", 2)
+ if len(part) < 2 {
+ continue
+ }
+ if strings.HasPrefix(part[0], name) {
+ env[part[0]] = part[1]
+ }
+ }
+ } else {
+ // if only a pass-through variable is given, clean it up.
+ val, _ := os.LookupEnv(name)
+ env[name] = val
+ }
}
return nil
}
@@ -149,3 +163,12 @@ func ValidateFileName(filename string) error {
}
return nil
}
+
+// ValidURL checks a string urlStr is a url or not
+func ValidURL(urlStr string) error {
+ _, err := url.ParseRequestURI(urlStr)
+ if err != nil {
+ return errors.Wrapf(err, "invalid url path: %q", urlStr)
+ }
+ return nil
+}
diff --git a/cmd/podman/shared/pod.go b/cmd/podman/shared/pod.go
index 3f4cb0312..ab6d1f144 100644
--- a/cmd/podman/shared/pod.go
+++ b/cmd/podman/shared/pod.go
@@ -4,6 +4,7 @@ import (
"strconv"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
"github.com/cri-o/ocicni/pkg/ocicni"
"github.com/docker/go-connections/nat"
"github.com/pkg/errors"
@@ -29,7 +30,7 @@ func GetPodStatus(pod *libpod.Pod) (string, error) {
return CreatePodStatusResults(ctrStatuses)
}
-func CreatePodStatusResults(ctrStatuses map[string]libpod.ContainerStatus) (string, error) {
+func CreatePodStatusResults(ctrStatuses map[string]define.ContainerStatus) (string, error) {
ctrNum := len(ctrStatuses)
if ctrNum == 0 {
return PodStateCreated, nil
@@ -43,15 +44,15 @@ func CreatePodStatusResults(ctrStatuses map[string]libpod.ContainerStatus) (stri
}
for _, ctrStatus := range ctrStatuses {
switch ctrStatus {
- case libpod.ContainerStateExited:
+ case define.ContainerStateExited:
fallthrough
- case libpod.ContainerStateStopped:
+ case define.ContainerStateStopped:
statuses[PodStateStopped]++
- case libpod.ContainerStateRunning:
+ case define.ContainerStateRunning:
statuses[PodStateRunning]++
- case libpod.ContainerStatePaused:
+ case define.ContainerStatePaused:
statuses[PodStatePaused]++
- case libpod.ContainerStateCreated, libpod.ContainerStateConfigured:
+ case define.ContainerStateCreated, define.ContainerStateConfigured:
statuses[PodStateCreated]++
default:
statuses[PodStateErrored]++
diff --git a/cmd/podman/sign.go b/cmd/podman/sign.go
index 0c25eec62..1333cf441 100644
--- a/cmd/podman/sign.go
+++ b/cmd/podman/sign.go
@@ -60,7 +60,7 @@ func signCmd(c *cliconfig.SignValues) error {
if err != nil {
return errors.Wrapf(err, "could not create runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
signby := c.SignBy
if signby == "" {
diff --git a/cmd/podman/start.go b/cmd/podman/start.go
index bd34010f2..737a6d9f1 100644
--- a/cmd/podman/start.go
+++ b/cmd/podman/start.go
@@ -2,7 +2,7 @@ package main
import (
"github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/adapter"
"github.com/opentracing/opentracing-go"
"github.com/pkg/errors"
@@ -35,7 +35,7 @@ func init() {
startCommand.SetUsageTemplate(UsageTemplate())
flags := startCommand.Flags()
flags.BoolVarP(&startCommand.Attach, "attach", "a", false, "Attach container's STDOUT and STDERR")
- 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.StringVar(&startCommand.DetachKeys, "detach-keys", "", "Override 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(&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", false, "Proxy received signals to the process (default true if attaching, false otherwise)")
@@ -62,14 +62,14 @@ func startCmd(c *cliconfig.StartValues) error {
sigProxy := c.SigProxy || attach
if sigProxy && !attach {
- return errors.Wrapf(libpod.ErrInvalidArg, "you cannot use sig-proxy without --attach")
+ return errors.Wrapf(define.ErrInvalidArg, "you cannot use sig-proxy without --attach")
}
runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
exitCode, err = runtime.Start(getContext(), c, sigProxy)
return err
}
diff --git a/cmd/podman/stats.go b/cmd/podman/stats.go
index c2b2a688c..3accae1b6 100644
--- a/cmd/podman/stats.go
+++ b/cmd/podman/stats.go
@@ -12,6 +12,7 @@ import (
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
"github.com/docker/go-units"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -92,7 +93,7 @@ func statsCmd(c *cliconfig.StatsValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
times := -1
if c.NoStream {
@@ -100,9 +101,8 @@ func statsCmd(c *cliconfig.StatsValues) error {
}
var ctrs []*libpod.Container
- var containerFunc func() ([]*libpod.Container, error)
- containerFunc = runtime.GetRunningContainers
+ containerFunc := runtime.GetRunningContainers
if len(c.InputArgs) > 0 {
containerFunc = func() ([]*libpod.Container, error) { return runtime.GetContainersByList(c.InputArgs) }
} else if latest {
@@ -127,7 +127,7 @@ func statsCmd(c *cliconfig.StatsValues) error {
initialStats, err := ctr.GetContainerStats(&libpod.ContainerStats{})
if err != nil {
// when doing "all", dont worry about containers that are not running
- if c.All && errors.Cause(err) == libpod.ErrCtrRemoved || errors.Cause(err) == libpod.ErrNoSuchCtr || errors.Cause(err) == libpod.ErrCtrStateInvalid {
+ if c.All && errors.Cause(err) == define.ErrCtrRemoved || errors.Cause(err) == define.ErrNoSuchCtr || errors.Cause(err) == define.ErrCtrStateInvalid {
continue
}
return err
@@ -148,7 +148,7 @@ func statsCmd(c *cliconfig.StatsValues) error {
id := ctr.ID()
if _, ok := containerStats[ctr.ID()]; !ok {
initialStats, err := ctr.GetContainerStats(&libpod.ContainerStats{})
- if errors.Cause(err) == libpod.ErrCtrRemoved || errors.Cause(err) == libpod.ErrNoSuchCtr || errors.Cause(err) == libpod.ErrCtrStateInvalid {
+ if errors.Cause(err) == define.ErrCtrRemoved || errors.Cause(err) == define.ErrNoSuchCtr || errors.Cause(err) == define.ErrCtrStateInvalid {
// skip dealing with a container that is gone
continue
}
@@ -158,7 +158,7 @@ func statsCmd(c *cliconfig.StatsValues) error {
containerStats[id] = initialStats
}
stats, err := ctr.GetContainerStats(containerStats[id])
- if err != nil && errors.Cause(err) != libpod.ErrNoSuchCtr {
+ if err != nil && errors.Cause(err) != define.ErrNoSuchCtr {
return err
}
// replace the previous measurement with the current one
@@ -174,7 +174,9 @@ func statsCmd(c *cliconfig.StatsValues) error {
tm.MoveCursor(1, 1)
tm.Flush()
}
- outputStats(reportStats, format)
+ if err := outputStats(reportStats, format); err != nil {
+ return err
+ }
time.Sleep(time.Second)
}
return nil
@@ -198,7 +200,7 @@ func outputStats(stats []*libpod.ContainerStats, format string) error {
}
out = formats.StdoutTemplateArray{Output: statsToGeneric(outputStats, []statsOutputParams{}), Template: format, Fields: mapOfHeaders}
}
- return formats.Writer(out).Out()
+ return out.Out()
}
func genStatsFormat(format string) string {
diff --git a/cmd/podman/stop.go b/cmd/podman/stop.go
index d88c90deb..e04d8a12b 100644
--- a/cmd/podman/stop.go
+++ b/cmd/podman/stop.go
@@ -2,7 +2,7 @@ package main
import (
"github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/adapter"
"github.com/opentracing/opentracing-go"
"github.com/pkg/errors"
@@ -40,8 +40,8 @@ func init() {
flags := stopCommand.Flags()
flags.BoolVarP(&stopCommand.All, "all", "a", false, "Stop all running containers")
flags.BoolVarP(&stopCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
- flags.UintVar(&stopCommand.Timeout, "time", libpod.CtrRemoveTimeout, "Seconds to wait for stop before killing the container")
- flags.UintVarP(&stopCommand.Timeout, "timeout", "t", libpod.CtrRemoveTimeout, "Seconds to wait for stop before killing the container")
+ flags.UintVar(&stopCommand.Timeout, "time", define.CtrRemoveTimeout, "Seconds to wait for stop before killing the container")
+ flags.UintVarP(&stopCommand.Timeout, "timeout", "t", define.CtrRemoveTimeout, "Seconds to wait for stop before killing the container")
markFlagHiddenForRemoteClient("latest", flags)
}
@@ -60,7 +60,7 @@ func stopCmd(c *cliconfig.StopValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
ok, failures, err := runtime.StopContainers(getContext(), c)
if err != nil {
diff --git a/cmd/podman/system_df.go b/cmd/podman/system_df.go
index 840916547..6b9824a79 100644
--- a/cmd/podman/system_df.go
+++ b/cmd/podman/system_df.go
@@ -1,3 +1,5 @@
+//+build !remoteclient
+
package main
import (
@@ -12,8 +14,9 @@ import (
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/libpod/image"
- units "github.com/docker/go-units"
+ "github.com/docker/go-units"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -103,7 +106,7 @@ func dfSystemCmd(c *cliconfig.SystemDfValues) error {
if err != nil {
return errors.Wrapf(err, "Could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
ctx := getContext()
@@ -128,11 +131,10 @@ func dfSystemCmd(c *cliconfig.SystemDfValues) error {
if c.Format != "" {
format = strings.Replace(c.Format, `\t`, "\t", -1)
}
- generateSysDfOutput(systemDfDiskUsages, format)
- return nil
+ return generateSysDfOutput(systemDfDiskUsages, format)
}
-func generateSysDfOutput(systemDfDiskUsages []systemDfDiskUsage, format string) {
+func generateSysDfOutput(systemDfDiskUsages []systemDfDiskUsage, format string) error {
var systemDfHeader = map[string]string{
"Type": "TYPE",
"Total": "TOTAL",
@@ -141,7 +143,7 @@ func generateSysDfOutput(systemDfDiskUsages []systemDfDiskUsage, format string)
"Reclaimable": "RECLAIMABLE",
}
out := formats.StdoutTemplateArray{Output: systemDfDiskUsageToGeneric(systemDfDiskUsages), Template: format, Fields: systemDfHeader}
- formats.Writer(out).Out()
+ return out.Out()
}
func getDiskUsage(ctx context.Context, runtime *libpod.Runtime, metaData dfMetaData) ([]systemDfDiskUsage, error) {
@@ -358,7 +360,7 @@ func ctrIsActive(ctr *libpod.Container) (bool, error) {
if err != nil {
return false, err
}
- return state == libpod.ContainerStatePaused || state == libpod.ContainerStateRunning, nil
+ return state == define.ContainerStatePaused || state == define.ContainerStateRunning, nil
}
func activeContainers(containers []*libpod.Container) (map[string]*libpod.Container, error) {
@@ -544,17 +546,18 @@ func imagesVerboseOutput(ctx context.Context, metaData dfMetaData) error {
"Created": "CREATED",
"Size": "SIZE",
"SharedSize": "SHARED SIZE",
- "UniqueSize": "UNQUE SIZE",
+ "UniqueSize": "UNIQUE SIZE",
"Containers": "CONTAINERS",
}
imagesVerboseDiskUsage, err := getImageVerboseDiskUsage(ctx, metaData.images, metaData.imagesUsedbyCtrMap)
if err != nil {
return errors.Wrapf(err, "error getting verbose output of images")
}
- os.Stderr.WriteString("Images space usage:\n\n")
+ if _, err := os.Stderr.WriteString("Images space usage:\n\n"); err != nil {
+ return err
+ }
out := formats.StdoutTemplateArray{Output: systemDfImageVerboseDiskUsageToGeneric(imagesVerboseDiskUsage), Template: imageVerboseFormat, Fields: imageVerboseHeader}
- formats.Writer(out).Out()
- return nil
+ return out.Out()
}
func containersVerboseOutput(ctx context.Context, metaData dfMetaData) error {
@@ -572,10 +575,12 @@ func containersVerboseOutput(ctx context.Context, metaData dfMetaData) error {
if err != nil {
return errors.Wrapf(err, "error getting verbose output of containers")
}
- os.Stderr.WriteString("\nContainers space usage:\n\n")
+ if _, err := os.Stderr.WriteString("\nContainers space usage:\n\n"); err != nil {
+ return err
+ }
out := formats.StdoutTemplateArray{Output: systemDfContainerVerboseDiskUsageToGeneric(containersVerboseDiskUsage), Template: containerVerboseFormat, Fields: containerVerboseHeader}
- formats.Writer(out).Out()
- return nil
+ return out.Out()
+
}
func volumesVerboseOutput(ctx context.Context, metaData dfMetaData) error {
@@ -586,12 +591,13 @@ func volumesVerboseOutput(ctx context.Context, metaData dfMetaData) error {
}
volumesVerboseDiskUsage, err := getVolumeVerboseDiskUsage(metaData.volumes, metaData.volumeUsedByContainerMap)
if err != nil {
- return errors.Wrapf(err, "error getting verbose ouput of volumes")
+ return errors.Wrapf(err, "error getting verbose output of volumes")
+ }
+ if _, err := os.Stderr.WriteString("\nLocal Volumes space usage:\n\n"); err != nil {
+ return err
}
- os.Stderr.WriteString("\nLocal Volumes space usage:\n\n")
out := formats.StdoutTemplateArray{Output: systemDfVolumeVerboseDiskUsageToGeneric(volumesVerboseDiskUsage), Template: volumeVerboseFormat, Fields: volumeVerboseHeader}
- formats.Writer(out).Out()
- return nil
+ return out.Out()
}
func verboseOutput(ctx context.Context, metaData dfMetaData) error {
diff --git a/cmd/podman/system_prune.go b/cmd/podman/system_prune.go
index d5b218cd8..b499d8dd2 100644
--- a/cmd/podman/system_prune.go
+++ b/cmd/podman/system_prune.go
@@ -76,27 +76,33 @@ Are you sure you want to continue? [y/N] `, volumeString)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
-
- rmWorkers := shared.Parallelize("rm")
- ctx := getContext()
- fmt.Println("Deleted Containers")
- ok, failures, lasterr := runtime.Prune(ctx, rmWorkers, false)
- printCmdResults(ok, failures)
+ defer runtime.DeferredShutdown(false)
+ // We must clean out pods first because if they may have infra containers
fmt.Println("Deleted Pods")
pruneValues := cliconfig.PodPruneValues{
PodmanCommand: c.PodmanCommand,
Force: c.Force,
}
- ok, failures, err = runtime.PrunePods(ctx, &pruneValues)
+ ctx := getContext()
+ ok, failures, lasterr := runtime.PrunePods(ctx, &pruneValues)
+
+ if err := printCmdResults(ok, failures); err != nil {
+ return err
+ }
+
+ rmWorkers := shared.Parallelize("rm")
+ fmt.Println("Deleted Containers")
+ ok, failures, err = runtime.Prune(ctx, rmWorkers, false)
if err != nil {
if lasterr != nil {
- logrus.Errorf("%q", lasterr)
+ logrus.Errorf("%q", err)
}
lasterr = err
}
- printCmdResults(ok, failures)
+ if err := printCmdResults(ok, failures); err != nil {
+ return err
+ }
if c.Bool("volumes") {
fmt.Println("Deleted Volumes")
diff --git a/cmd/podman/tag.go b/cmd/podman/tag.go
index 58f221e26..eb43d695c 100644
--- a/cmd/podman/tag.go
+++ b/cmd/podman/tag.go
@@ -42,7 +42,7 @@ func tagCmd(c *cliconfig.TagValues) error {
if err != nil {
return errors.Wrapf(err, "could not create runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
newImage, err := runtime.NewImageFromLocal(args[0])
if err != nil {
diff --git a/cmd/podman/top.go b/cmd/podman/top.go
index 8583eccb5..bfba90fc0 100644
--- a/cmd/podman/top.go
+++ b/cmd/podman/top.go
@@ -7,14 +7,14 @@ import (
"text/tabwriter"
"github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/adapter"
+ "github.com/containers/libpod/pkg/util"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
func getDescriptorString() string {
- descriptors, err := libpod.GetContainerPidInformationDescriptors()
+ descriptors, err := util.GetContainerPidInformationDescriptors()
if err == nil {
return fmt.Sprintf(`
Format Descriptors:
@@ -57,7 +57,7 @@ func init() {
flags := topCommand.Flags()
flags.SetInterspersed(false)
flags.BoolVar(&topCommand.ListDescriptors, "list-descriptors", false, "")
- flags.MarkHidden("list-descriptors")
+ markFlagHidden(flags, "list-descriptors")
flags.BoolVarP(&topCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
markFlagHiddenForRemoteClient("latest", flags)
}
@@ -67,7 +67,7 @@ func topCmd(c *cliconfig.TopValues) error {
args := c.InputArgs
if c.ListDescriptors {
- descriptors, err := libpod.GetContainerPidInformationDescriptors()
+ descriptors, err := util.GetContainerPidInformationDescriptors()
if err != nil {
return err
}
@@ -83,7 +83,7 @@ func topCmd(c *cliconfig.TopValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
psOutput, err := runtime.Top(c)
if err != nil {
@@ -91,8 +91,9 @@ func topCmd(c *cliconfig.TopValues) error {
}
w := tabwriter.NewWriter(os.Stdout, 5, 1, 3, ' ', 0)
for _, proc := range psOutput {
- fmt.Fprintln(w, proc)
+ if _, err := fmt.Fprintln(w, proc); err != nil {
+ return err
+ }
}
- w.Flush()
- return nil
+ return w.Flush()
}
diff --git a/cmd/podman/tree.go b/cmd/podman/tree.go
index 6490c609d..904a0d375 100644
--- a/cmd/podman/tree.go
+++ b/cmd/podman/tree.go
@@ -55,7 +55,7 @@ func treeCmd(c *cliconfig.TreeValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
imageInfo, layerInfoMap, img, err := runtime.Tree(c)
if err != nil {
return err
@@ -72,7 +72,11 @@ func printTree(imageInfo *image.InfoImage, layerInfoMap map[string]*image.LayerI
fmt.Printf("Image ID: %s\n", imageInfo.ID[:12])
fmt.Printf("Tags:\t %s\n", imageInfo.Tags)
fmt.Printf("Size:\t %v\n", units.HumanSizeWithPrecision(float64(*size), 4))
- fmt.Printf(fmt.Sprintf("Image Layers\n"))
+ if img.TopLayer() != "" {
+ fmt.Printf("Image Layers\n")
+ } else {
+ fmt.Printf("No Image Layers\n")
+ }
if !whatRequires {
// fill imageInfo with layers associated with image.
@@ -103,7 +107,7 @@ func printImageChildren(layerMap map[string]*image.LayerInfo, layerID string, pr
if !ok {
return fmt.Errorf("lookup error: layerid %s, not found", layerID)
}
- fmt.Printf(prefix)
+ fmt.Print(prefix)
//initialize intend with middleItem to reduce middleItem checks.
intend := middleItem
@@ -123,7 +127,7 @@ func printImageChildren(layerMap map[string]*image.LayerInfo, layerID string, pr
}
fmt.Printf("%sID: %s Size: %7v%s\n", intend, ll.ID[:12], units.HumanSizeWithPrecision(float64(ll.Size), 4), tags)
for count, childID := range ll.ChildID {
- if err := printImageChildren(layerMap, childID, prefix, (count == len(ll.ChildID)-1)); err != nil {
+ if err := printImageChildren(layerMap, childID, prefix, count == len(ll.ChildID)-1); err != nil {
return err
}
}
diff --git a/cmd/podman/trust_set_show.go b/cmd/podman/trust_set_show.go
index b615f6266..7d2a5ddc3 100644
--- a/cmd/podman/trust_set_show.go
+++ b/cmd/podman/trust_set_show.go
@@ -7,7 +7,6 @@ import (
"strings"
"github.com/containers/buildah/pkg/formats"
- "github.com/containers/image/types"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/libpod/image"
@@ -57,7 +56,7 @@ func init() {
showTrustCommand.SetUsageTemplate(UsageTemplate())
setFlags := setTrustCommand.Flags()
setFlags.StringVar(&setTrustCommand.PolicyPath, "policypath", "", "")
- setFlags.MarkHidden("policypath")
+ markFlagHidden(setFlags, "policypath")
setFlags.StringSliceVarP(&setTrustCommand.PubKeysFile, "pubkeysfile", "f", []string{}, `Path of installed public key(s) to trust for TARGET.
Absolute path to keys is added to policy.json. May
used multiple times to define multiple public keys.
@@ -68,9 +67,9 @@ File(s) must exist before using this command`)
showFlags.BoolVarP(&showTrustCommand.Json, "json", "j", false, "Output as json")
showFlags.StringVar(&showTrustCommand.PolicyPath, "policypath", "", "")
showFlags.BoolVar(&showTrustCommand.Raw, "raw", false, "Output raw policy file")
- showFlags.MarkHidden("policypath")
+ markFlagHidden(showFlags, "policypath")
showFlags.StringVar(&showTrustCommand.RegistryPath, "registrypath", "", "")
- showFlags.MarkHidden("registrypath")
+ markFlagHidden(showFlags, "registrypath")
}
func showTrustCmd(c *cliconfig.ShowTrustValues) error {
@@ -119,7 +118,7 @@ func showTrustCmd(c *cliconfig.ShowTrustValues) error {
}
outjson = policyJSON
out := formats.JSONStruct{Output: outjson}
- return formats.Writer(out).Out()
+ return out.Out()
}
showOutputMap, err := getPolicyShowOutput(policyContentStruct, systemRegistriesDirPath)
@@ -127,7 +126,7 @@ func showTrustCmd(c *cliconfig.ShowTrustValues) error {
return errors.Wrapf(err, "could not show trust policies")
}
out := formats.StdoutTemplateArray{Output: showOutputMap, Template: "{{.Repo}}\t{{.Trusttype}}\t{{.GPGid}}\t{{.Sigstore}}"}
- return formats.Writer(out).Out()
+ return out.Out()
}
func setTrustCmd(c *cliconfig.SetTrustValues) error {
@@ -238,10 +237,6 @@ func isValidTrustType(t string) bool {
return false
}
-func getDefaultPolicyPath() string {
- return trust.DefaultPolicyPath(&types.SystemContext{})
-}
-
func getPolicyJSON(policyContentStruct trust.PolicyContent, systemRegistriesDirPath string) (map[string]map[string]interface{}, error) {
registryConfigs, err := trust.LoadAndMergeConfig(systemRegistriesDirPath)
if err != nil {
@@ -259,15 +254,12 @@ func getPolicyJSON(policyContentStruct trust.PolicyContent, systemRegistriesDirP
policyJSON[repo]["type"] = repoval[0].Type
policyJSON[repo]["transport"] = transname
keyarr := []string{}
- uids := []string{}
for _, repoele := range repoval {
if len(repoele.KeyPath) > 0 {
keyarr = append(keyarr, repoele.KeyPath)
- uids = append(uids, trust.GetGPGIdFromKeyPath(repoele.KeyPath)...)
}
if len(repoele.KeyData) > 0 {
- keyarr = append(keyarr, string(repoele.KeyData))
- uids = append(uids, trust.GetGPGIdFromKeyData(string(repoele.KeyData))...)
+ keyarr = append(keyarr, repoele.KeyData)
}
}
policyJSON[repo]["keys"] = keyarr
@@ -313,16 +305,17 @@ func getPolicyShowOutput(policyContentStruct trust.PolicyContent, systemRegistri
Repo: repo,
Trusttype: repoval[0].Type,
}
- keyarr := []string{}
+ // TODO - keyarr is not used and I don't know its intent; commenting out for now for someone to fix later
+ //keyarr := []string{}
uids := []string{}
for _, repoele := range repoval {
if len(repoele.KeyPath) > 0 {
- keyarr = append(keyarr, repoele.KeyPath)
+ //keyarr = append(keyarr, repoele.KeyPath)
uids = append(uids, trust.GetGPGIdFromKeyPath(repoele.KeyPath)...)
}
if len(repoele.KeyData) > 0 {
- keyarr = append(keyarr, string(repoele.KeyData))
- uids = append(uids, trust.GetGPGIdFromKeyData(string(repoele.KeyData))...)
+ //keyarr = append(keyarr, string(repoele.KeyData))
+ uids = append(uids, trust.GetGPGIdFromKeyData(repoele.KeyData)...)
}
}
tempTrustShowOutput.GPGid = strings.Join(uids, ", ")
diff --git a/cmd/podman/umount.go b/cmd/podman/umount.go
index ddbd00bd5..c3d81d3a8 100644
--- a/cmd/podman/umount.go
+++ b/cmd/podman/umount.go
@@ -52,7 +52,7 @@ func umountCmd(c *cliconfig.UmountValues) error {
if err != nil {
return errors.Wrapf(err, "error creating runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
ok, failures, err := runtime.UmountRootFilesystems(getContext(), c)
if err != nil {
diff --git a/cmd/podman/unpause.go b/cmd/podman/unpause.go
index 2cd6846fe..382b64e97 100644
--- a/cmd/podman/unpause.go
+++ b/cmd/podman/unpause.go
@@ -1,11 +1,10 @@
package main
import (
- "os"
-
"github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/adapter"
+ "github.com/containers/libpod/pkg/rootless"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@@ -38,7 +37,7 @@ func init() {
}
func unpauseCmd(c *cliconfig.UnpauseValues) error {
- if os.Geteuid() != 0 {
+ if rootless.IsRootless() && !remoteclient {
return errors.New("unpause is not supported for rootless containers")
}
@@ -46,7 +45,7 @@ func unpauseCmd(c *cliconfig.UnpauseValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
args := c.InputArgs
if len(args) < 1 && !c.All {
@@ -54,7 +53,7 @@ func unpauseCmd(c *cliconfig.UnpauseValues) error {
}
ok, failures, err := runtime.UnpauseContainers(getContext(), c)
if err != nil {
- if errors.Cause(err) == libpod.ErrNoSuchCtr {
+ if errors.Cause(err) == define.ErrNoSuchCtr {
if len(c.InputArgs) > 1 {
exitCode = 125
} else {
diff --git a/cmd/podman/unshare.go b/cmd/podman/unshare.go
index 4a4e371db..31ce441f4 100644
--- a/cmd/podman/unshare.go
+++ b/cmd/podman/unshare.go
@@ -1,4 +1,4 @@
-// +build linux
+// +build !remoteclient
package main
@@ -8,8 +8,7 @@ import (
"os/exec"
"github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/containers/libpod/cmd/podman/libpodruntime"
- "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/adapter"
"github.com/containers/libpod/pkg/rootless"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -41,10 +40,10 @@ func init() {
flags.SetInterspersed(false)
}
-func unshareEnv(config *libpod.RuntimeConfig) []string {
+func unshareEnv(graphroot, runroot string) []string {
return append(os.Environ(), "_CONTAINERS_USERNS_CONFIGURED=done",
- fmt.Sprintf("CONTAINERS_GRAPHROOT=%s", config.StorageConfig.GraphRoot),
- fmt.Sprintf("CONTAINERS_RUNROOT=%s", config.StorageConfig.RunRoot))
+ fmt.Sprintf("CONTAINERS_GRAPHROOT=%s", graphroot),
+ fmt.Sprintf("CONTAINERS_RUNROOT=%s", runroot))
}
// unshareCmd execs whatever using the ID mappings that we want to use for ourselves
@@ -63,7 +62,7 @@ func unshareCmd(c *cliconfig.PodmanCommand) error {
c.InputArgs = []string{shell}
}
- runtime, err := libpodruntime.GetRuntime(getContext(), c)
+ runtime, err := adapter.GetRuntime(getContext(), c)
if err != nil {
return err
}
@@ -73,7 +72,7 @@ func unshareCmd(c *cliconfig.PodmanCommand) error {
}
cmd := exec.Command(c.InputArgs[0], c.InputArgs[1:]...)
- cmd.Env = unshareEnv(runtimeConfig)
+ cmd.Env = unshareEnv(runtimeConfig.StorageConfig.GraphRoot, runtimeConfig.StorageConfig.RunRoot)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
diff --git a/cmd/podman/utils.go b/cmd/podman/utils.go
index 986db469e..c0ddaba4e 100644
--- a/cmd/podman/utils.go
+++ b/cmd/podman/utils.go
@@ -3,27 +3,12 @@ package main
import (
"fmt"
"reflect"
+ "runtime/debug"
+ "github.com/sirupsen/logrus"
"github.com/spf13/pflag"
)
-// printParallelOutput takes the map of parallel worker results and outputs them
-// to stdout
-func printParallelOutput(m map[string]error, errCount int) error {
- var lastError error
- for cid, result := range m {
- if result != nil {
- if errCount > 1 {
- fmt.Println(result.Error())
- }
- lastError = result
- continue
- }
- fmt.Println(cid)
- }
- return lastError
-}
-
// print results from CLI command
func printCmdResults(ok []string, failures map[string]error) error {
for _, id := range ok {
@@ -48,6 +33,33 @@ func printCmdResults(ok []string, failures map[string]error) error {
// on the remote-client
func markFlagHiddenForRemoteClient(flagName string, flags *pflag.FlagSet) {
if remoteclient {
- flags.MarkHidden(flagName)
+ if err := flags.MarkHidden(flagName); err != nil {
+ debug.PrintStack()
+ logrus.Errorf("unable to mark %s as hidden in the remote-client", flagName)
+ }
+ }
+}
+
+// markFlagHidden is a helper function to log an error if marking
+// a flag as hidden happens to fail
+func markFlagHidden(flags *pflag.FlagSet, flag string) {
+ if err := flags.MarkHidden(flag); err != nil {
+ logrus.Errorf("unable to mark flag '%s' as hidden: %q", flag, err)
+ }
+}
+
+func aliasFlags(f *pflag.FlagSet, name string) pflag.NormalizedName {
+ switch name {
+ case "healthcheck-command":
+ name = "health-cmd"
+ case "healthcheck-interval":
+ name = "health-interval"
+ case "healthcheck-retries":
+ name = "health-retries"
+ case "healthcheck-start-period":
+ name = "health-start-period"
+ case "healthcheck-timeout":
+ name = "health-timeout"
}
+ return pflag.NormalizedName(name)
}
diff --git a/cmd/podman/varlink.go b/cmd/podman/varlink.go
index 698a30d84..92315cd6b 100644
--- a/cmd/podman/varlink.go
+++ b/cmd/podman/varlink.go
@@ -83,7 +83,7 @@ func varlinkCmd(c *cliconfig.VarlinkValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
var varlinkInterfaces = []*iopodman.VarlinkInterface{varlinkapi.New(&c.PodmanCommand, runtime)}
// Register varlink service. The metadata can be retrieved with:
diff --git a/cmd/podman/varlink/io.podman.varlink b/cmd/podman/varlink/io.podman.varlink
index ed7b49c68..f5f3250f7 100644
--- a/cmd/podman/varlink/io.podman.varlink
+++ b/cmd/podman/varlink/io.podman.varlink
@@ -69,7 +69,8 @@ type Image (
containers: int,
labels: [string]string,
isParent: bool,
- topLayer: string
+ topLayer: string,
+ readOnly: bool
)
# ImageHistory describes the returned structure from ImageHistory.
@@ -144,10 +145,11 @@ type PsOpts (
last: ?int,
latest: ?bool,
noTrunc: ?bool,
- pod: ?bool,
- quiet: ?bool,
- sort: ?string,
- sync: ?bool
+ pod: ?bool,
+ quiet: ?bool,
+ size: ?bool,
+ sort: ?string,
+ sync: ?bool
)
type PsContainer (
@@ -207,7 +209,7 @@ type ContainerNameSpace (
ipc: string
)
-# InfoDistribution describes the the host's distribution
+# InfoDistribution describes the host's distribution
type InfoDistribution (
distribution: string,
version: string
@@ -498,6 +500,25 @@ type DiffInfo(
changeType: string
)
+type ExecOpts(
+ # container name or id
+ name: string,
+ # Create pseudo tty
+ tty: bool,
+ # privileged access in container
+ privileged: bool,
+ # command to execute in container
+ cmd: []string,
+ # user to use in container
+ user: ?string,
+ # workdir to run command in container
+ workdir: ?string,
+ # slice of keyword=value environment variables
+ env: ?[]string,
+ # string of detach keys
+ detachKeys: ?string
+)
+
# GetVersion returns version and build information of the podman service
method GetVersion() -> (
version: string,
@@ -671,7 +692,7 @@ method PauseContainer(name: string) -> (container: string)
# See also [PauseContainer](#PauseContainer).
method UnpauseContainer(name: string) -> (container: string)
-# Attach takes the name or ID of a container and sets up a the ability to remotely attach to its console. The start
+# Attach takes the name or ID of a container and sets up the ability to remotely attach to its console. The start
# bool is whether you wish to start the container in question first.
method Attach(name: string, detachKeys: string, start: bool) -> ()
@@ -744,7 +765,7 @@ method BuildImage(build: BuildInfo) -> (image: MoreResponse)
# This function is not implemented yet.
# method CreateImage() -> (notimplemented: NotImplemented)
-# InspectImage takes the name or ID of an image and returns a string respresentation of data associated with the
+# InspectImage takes the name or ID of an image and returns a string representation of data associated with the
#image. You must serialize the string into JSON to use it further. An [ImageNotFound](#ImageNotFound) error will
# be returned if the image cannot be found.
method InspectImage(name: string) -> (image: string)
@@ -802,15 +823,15 @@ method DeleteUnusedImages() -> (images: []string)
# attributes: _CMD, ENTRYPOINT, ENV, EXPOSE, LABEL, ONBUILD, STOPSIGNAL, USER, VOLUME, and WORKDIR_. To pause the
# container while it is being committed, pass a _true_ bool for the pause argument. If the container cannot
# be found by the ID or name provided, a (ContainerNotFound)[#ContainerNotFound] error will be returned; otherwise,
-# the resulting image's ID will be returned as a string.
-method Commit(name: string, image_name: string, changes: []string, author: string, message: string, pause: bool, manifestType: string) -> (image: string)
+# the resulting image's ID will be returned as a string inside a MoreResponse.
+method Commit(name: string, image_name: string, changes: []string, author: string, message: string, pause: bool, manifestType: string) -> (reply: MoreResponse)
# ImportImage imports an image from a source (like tarball) into local storage. The image can have additional
# descriptions added to it using the message and changes options. See also [ExportImage](ExportImage).
method ImportImage(source: string, reference: string, message: string, changes: []string, delete: bool) -> (image: string)
# ExportImage takes the name or ID of an image and exports it to a destination like a tarball. There is also
-# a booleon option to force compression. It also takes in a string array of tags to be able to save multiple
+# a boolean option to force compression. It also takes in a string array of tags to be able to save multiple
# tags of the same image to a tarball (each tag should be of the form <image>:<tag>). Upon completion, the ID
# of the image is returned. If the image cannot be found in local storage, an [ImageNotFound](#ImageNotFound)
# error will be returned. See also [ImportImage](ImportImage).
@@ -915,7 +936,7 @@ method ListPods() -> (pods: []ListPodData)
# ~~~
method GetPod(name: string) -> (pod: ListPodData)
-# InspectPod takes the name or ID of an image and returns a string respresentation of data associated with the
+# InspectPod takes the name or ID of an image and returns a string representation of data associated with the
# pod. You must serialize the string into JSON to use it further. A [PodNotFound](#PodNotFound) error will
# be returned if the pod cannot be found.
method InspectPod(name: string) -> (pod: string)
@@ -1098,6 +1119,9 @@ method ContainerRestore(name: string, keep: bool, tcpEstablished: bool) -> (id:
# ContainerRunlabel runs executes a command as described by a given container image label.
method ContainerRunlabel(runlabel: Runlabel) -> ()
+# ExecContainer executes a command in the given container.
+method ExecContainer(opts: ExecOpts) -> ()
+
# ListContainerMounts gathers all the mounted container mount points and returns them as an array
# of strings
# #### Example
diff --git a/cmd/podman/version.go b/cmd/podman/version.go
index 52a518db8..314b2e266 100644
--- a/cmd/podman/version.go
+++ b/cmd/podman/version.go
@@ -10,7 +10,7 @@ import (
"github.com/containers/buildah/pkg/formats"
"github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/adapter"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -40,9 +40,9 @@ func init() {
// versionCmd gets and prints version info for version command
func versionCmd(c *cliconfig.VersionValues) error {
- clientVersion, err := libpod.GetVersion()
+ clientVersion, err := define.GetVersion()
if err != nil {
- errors.Wrapf(err, "unable to determine version")
+ return errors.Wrapf(err, "unable to determine version")
}
versionOutputFormat := c.Format
@@ -57,24 +57,28 @@ func versionCmd(c *cliconfig.VersionValues) error {
default:
out = formats.StdoutTemplate{Output: clientVersion, Template: versionOutputFormat}
}
- return formats.Writer(out).Out()
+ return out.Out()
}
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
defer w.Flush()
if remote {
- fmt.Fprintf(w, "Client:\n")
+ if _, err := fmt.Fprintf(w, "Client:\n"); err != nil {
+ return err
+ }
}
formatVersion(w, clientVersion)
if remote {
- fmt.Fprintf(w, "\nService:\n")
+ if _, err := fmt.Fprintf(w, "\nService:\n"); err != nil {
+ return err
+ }
runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
serviceVersion, err := runtime.GetVersion()
if err != nil {
@@ -85,7 +89,7 @@ func versionCmd(c *cliconfig.VersionValues) error {
return nil
}
-func formatVersion(writer io.Writer, version libpod.Version) {
+func formatVersion(writer io.Writer, version define.Version) {
fmt.Fprintf(writer, "Version:\t%s\n", version.Version)
fmt.Fprintf(writer, "RemoteAPI Version:\t%d\n", version.RemoteAPIVersion)
fmt.Fprintf(writer, "Go Version:\t%s\n", version.GoVersion)
diff --git a/cmd/podman/volume_create.go b/cmd/podman/volume_create.go
index 84f6bba94..0897ab705 100644
--- a/cmd/podman/volume_create.go
+++ b/cmd/podman/volume_create.go
@@ -46,7 +46,7 @@ func volumeCreateCmd(c *cliconfig.VolumeCreateValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
if len(c.InputArgs) > 1 {
return errors.Errorf("too many arguments, create takes at most 1 argument")
diff --git a/cmd/podman/volume_inspect.go b/cmd/podman/volume_inspect.go
index e4b05f96a..1ebc5ce60 100644
--- a/cmd/podman/volume_inspect.go
+++ b/cmd/podman/volume_inspect.go
@@ -47,7 +47,7 @@ func volumeInspectCmd(c *cliconfig.VolumeInspectValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
vols, err := runtime.InspectVolumes(getContext(), c)
if err != nil {
diff --git a/cmd/podman/volume_ls.go b/cmd/podman/volume_ls.go
index 581e595cb..eda5685cf 100644
--- a/cmd/podman/volume_ls.go
+++ b/cmd/podman/volume_ls.go
@@ -76,7 +76,7 @@ func volumeLsCmd(c *cliconfig.VolumeLsValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
opts := volumeLsOptions{
Quiet: c.Quiet,
@@ -238,7 +238,7 @@ func generateVolLsOutput(volumes []*adapter.Volume, opts volumeLsOptions) error
}
out = formats.StdoutTemplateArray{Output: volLsToGeneric(lsOutput, []volumeLsJSONParams{}), Template: opts.Format, Fields: lsOutput[0].volHeaderMap()}
}
- return formats.Writer(out).Out()
+ return out.Out()
}
// generateVolumeFilterFuncs returns the true if the volume matches the filter set, otherwise it returns false.
diff --git a/cmd/podman/volume_prune.go b/cmd/podman/volume_prune.go
index 6dc9e2403..daea5a4d2 100644
--- a/cmd/podman/volume_prune.go
+++ b/cmd/podman/volume_prune.go
@@ -67,7 +67,7 @@ func volumePruneCmd(c *cliconfig.VolumePruneValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
// Prompt for confirmation if --force is not set
if !c.Force {
diff --git a/cmd/podman/volume_rm.go b/cmd/podman/volume_rm.go
index 77137eb7a..0141d06da 100644
--- a/cmd/podman/volume_rm.go
+++ b/cmd/podman/volume_rm.go
@@ -51,7 +51,7 @@ func volumeRmCmd(c *cliconfig.VolumeRmValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
deletedVolumeNames, err := runtime.RemoveVolumes(getContext(), c)
if err != nil {
if len(deletedVolumeNames) > 0 {
diff --git a/cmd/podman/wait.go b/cmd/podman/wait.go
index 380e861ed..d6a707bb8 100644
--- a/cmd/podman/wait.go
+++ b/cmd/podman/wait.go
@@ -55,7 +55,7 @@ func waitCmd(c *cliconfig.WaitValues) error {
if err != nil {
return errors.Wrapf(err, "error creating runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
ok, failures, err := runtime.WaitOnContainers(getContext(), c, interval)
if err != nil {