From 7b08aa78e4ede4c54fda6cd9917bb62e18d0d634 Mon Sep 17 00:00:00 2001 From: baude Date: Tue, 2 Jan 2018 16:29:43 -0600 Subject: Shortcut for most recent container It is desirable to have a shortcut for the most recently created container. We can now use "**latest" to represent the most recent container instead of its container ID or name. For example: Signed-off-by: baude Closes: #179 Approved by: baude --- cmd/podman/attach.go | 13 +++++++++---- cmd/podman/common.go | 8 ++++++++ cmd/podman/exec.go | 19 +++++++++++++++---- cmd/podman/inspect.go | 27 ++++++++++++++++++++------- cmd/podman/kill.go | 31 ++++++++++++++++++++++--------- cmd/podman/logs.go | 11 +++++++++-- cmd/podman/rm.go | 13 ++++++++++++- cmd/podman/start.go | 11 +++++++++-- cmd/podman/stats.go | 19 +++++++++++++++++-- cmd/podman/stop.go | 17 +++++++++++++---- cmd/podman/top.go | 13 ++++++++++--- 11 files changed, 144 insertions(+), 38 deletions(-) (limited to 'cmd') diff --git a/cmd/podman/attach.go b/cmd/podman/attach.go index 8c2c99fd5..e468964f6 100644 --- a/cmd/podman/attach.go +++ b/cmd/podman/attach.go @@ -19,6 +19,7 @@ var ( Name: "no-stdin", Usage: "Do not attach STDIN. The default is false.", }, + LatestFlag, } attachDescription = "The podman attach command allows you to attach to a running container using the container's ID or name, either to view its ongoing output or to control it interactively." attachCommand = cli.Command{ @@ -33,12 +34,12 @@ var ( func attachCmd(c *cli.Context) error { args := c.Args() + var ctr *libpod.Container if err := validateFlags(c, attachFlags); err != nil { return err } - - if len(c.Args()) < 1 || len(c.Args()) > 1 { - return errors.Errorf("attach requires the name or id of one running container") + if len(c.Args()) > 1 || (len(c.Args()) == 0 && !c.Bool("latest")) { + return errors.Errorf("attach requires the name or id of one running container or the latest flag") } runtime, err := getRuntime(c) @@ -47,7 +48,11 @@ func attachCmd(c *cli.Context) error { } defer runtime.Shutdown(false) - ctr, err := runtime.LookupContainer(args[0]) + if c.Bool("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]) diff --git a/cmd/podman/common.go b/cmd/podman/common.go index 5e670dcc8..e3997539a 100644 --- a/cmd/podman/common.go +++ b/cmd/podman/common.go @@ -14,6 +14,14 @@ import ( "github.com/urfave/cli" ) +var ( + stores = make(map[storage.Store]struct{}) + LatestFlag = cli.BoolFlag{ + Name: "latest, l", + Usage: "act on the latest container podman is aware of", + } +) + const crioConfigPath = "/etc/crio/crio.conf" func getRuntime(c *cli.Context) (*libpod.Runtime, error) { diff --git a/cmd/podman/exec.go b/cmd/podman/exec.go index 7a0bab617..07ef3a0cd 100644 --- a/cmd/podman/exec.go +++ b/cmd/podman/exec.go @@ -27,6 +27,7 @@ var ( Name: "user, u", Usage: "Sets the username or UID used and optionally the groupname or GID for the specified command", }, + LatestFlag, } execDescription = ` podman exec @@ -48,20 +49,30 @@ var ( func execCmd(c *cli.Context) error { var envs []string args := c.Args() - if len(args) < 1 { + var ctr *libpod.Container + var err error + argStart := 1 + if len(args) < 1 && !c.Bool("latest") { return errors.Errorf("you must provide one container name or id") } - if len(args) < 2 { + if len(args) < 2 && !c.Bool("latest") { return errors.Errorf("you must provide a command to exec") } - cmd := args[1:] + if c.Bool("latest") { + argStart = 0 + } + cmd := args[argStart:] runtime, err := getRuntime(c) if err != nil { return errors.Wrapf(err, "error creating libpod runtime") } defer runtime.Shutdown(false) - ctr, err := runtime.LookupContainer(args[0]) + if c.Bool("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]) } diff --git a/cmd/podman/inspect.go b/cmd/podman/inspect.go index 869d16911..dc5810492 100644 --- a/cmd/podman/inspect.go +++ b/cmd/podman/inspect.go @@ -33,6 +33,7 @@ var ( Name: "size", Usage: "Display total file size if the type is container", }, + LatestFlag, } inspectDescription = "This displays the low-level information on containers and images identified by name or ID. By default, this will render all results in a JSON array. If the container and image have the same name, this will return container JSON for unspecified type." inspectCommand = cli.Command{ @@ -47,7 +48,10 @@ var ( func inspectCmd(c *cli.Context) error { args := c.Args() - if len(args) == 0 { + inspectType := c.String("type") + latestContainer := c.Bool("latest") + var name string + if len(args) == 0 && !latestContainer { return errors.Errorf("container or image name must be specified: podman inspect [options [...]] name") } if len(args) > 1 { @@ -63,17 +67,26 @@ func inspectCmd(c *cli.Context) error { } defer runtime.Shutdown(false) - if c.String("type") != inspectTypeContainer && c.String("type") != inspectTypeImage && c.String("type") != inspectAll { + if !libpod.StringInSlice(inspectType, []string{inspectTypeContainer, inspectTypeImage, inspectAll}) { return errors.Errorf("the only recognized types are %q, %q, and %q", inspectTypeContainer, inspectTypeImage, inspectAll) } - - name := args[0] - + if !latestContainer { + name = args[0] + } + if latestContainer { + inspectType = inspectTypeContainer + } outputFormat := c.String("format") var data interface{} - switch c.String("type") { + switch inspectType { case inspectTypeContainer: - ctr, err := runtime.LookupContainer(name) + var ctr *libpod.Container + var err error + if latestContainer { + ctr, err = runtime.GetLatestContainer() + } else { + ctr, err = runtime.LookupContainer(name) + } if err != nil { return errors.Wrapf(err, "error looking up container %q", name) } diff --git a/cmd/podman/kill.go b/cmd/podman/kill.go index 776c7ef20..c24e68c54 100644 --- a/cmd/podman/kill.go +++ b/cmd/podman/kill.go @@ -1,10 +1,10 @@ package main import ( - "fmt" "os" "syscall" + "fmt" "github.com/docker/docker/pkg/signal" "github.com/pkg/errors" "github.com/urfave/cli" @@ -17,24 +17,29 @@ var ( Usage: "Signal to send to the container", Value: "KILL", }, + LatestFlag, } killDescription = "The main process inside each container specified will be sent SIGKILL, or any signal specified with option --signal." killCommand = cli.Command{ - Name: "kill", - Usage: "Kill one or more running containers with a specific signal", - Description: killDescription, - Flags: killFlags, - Action: killCmd, - ArgsUsage: "[CONTAINER_NAME_OR_ID]", + Name: "kill", + Usage: "Kill one or more running containers with a specific signal", + Description: killDescription, + Flags: killFlags, + Action: killCmd, + ArgsUsage: "[CONTAINER_NAME_OR_ID]", + UseShortOptionHandling: true, } ) // killCmd kills one or more containers with a signal func killCmd(c *cli.Context) error { args := c.Args() - if len(args) == 0 { + if len(args) == 0 && !c.Bool("latest") { return errors.Errorf("specify one or more containers to kill") } + if len(args) > 0 && c.Bool("latest") { + return errors.Errorf("you cannot specific any containers to kill with --latest") + } if err := validateFlags(c, killFlags); err != nil { return err } @@ -56,8 +61,16 @@ func killCmd(c *cli.Context) error { killSignal = uint(sysSignal) } + if c.Bool("latest") { + latestCtr, err := runtime.GetLatestContainer() + if err != nil { + return errors.Wrapf(err, "unable to get latest container") + } + args = append(args, latestCtr.ID()) + } + var lastError error - for _, container := range c.Args() { + for _, container := range args { ctr, err := runtime.LookupContainer(container) if err != nil { if lastError != nil { diff --git a/cmd/podman/logs.go b/cmd/podman/logs.go index 8745d5d7f..b31dce2d3 100644 --- a/cmd/podman/logs.go +++ b/cmd/podman/logs.go @@ -37,6 +37,7 @@ var ( Name: "tail", Usage: "Output the specified number of LINES at the end of the logs. Defaults to 0, which prints all lines", }, + LatestFlag, } logsDescription = "The podman logs command batch-retrieves whatever logs are present for a container at the time of execution. This does not guarantee execution" + "order when combined with podman run (i.e. your run may not have generated any logs at the time you execute podman logs" @@ -51,6 +52,8 @@ var ( ) func logsCmd(c *cli.Context) error { + var ctr *libpod.Container + var err error if err := validateFlags(c, logsFlags); err != nil { return err } @@ -62,7 +65,7 @@ func logsCmd(c *cli.Context) error { defer runtime.Shutdown(false) args := c.Args() - if len(args) != 1 { + if len(args) != 1 && !c.Bool("latest") { return errors.Errorf("'podman logs' requires exactly one container name/ID") } @@ -83,7 +86,11 @@ func logsCmd(c *cli.Context) error { tail: c.Uint64("tail"), } - ctr, err := runtime.LookupContainer(args[0]) + if c.Bool("latest") { + ctr, err = runtime.GetLatestContainer() + } else { + ctr, err = runtime.LookupContainer(args[0]) + } if err != nil { return err } diff --git a/cmd/podman/rm.go b/cmd/podman/rm.go index dcb8fac57..8dd3475c0 100644 --- a/cmd/podman/rm.go +++ b/cmd/podman/rm.go @@ -19,6 +19,7 @@ var ( Name: "all, a", Usage: "Remove all containers", }, + LatestFlag, } rmDescription = "Remove one or more containers" rmCommand = cli.Command{ @@ -46,7 +47,11 @@ func rmCmd(c *cli.Context) error { defer runtime.Shutdown(false) args := c.Args() - if len(args) == 0 && !c.Bool("all") { + if c.Bool("latest") && c.Bool("all") { + return errors.Errorf("--all and --latest cannot be used together") + } + + if len(args) == 0 && !c.Bool("all") && !c.Bool("latest") { return errors.Errorf("specify one or more containers to remove") } @@ -57,6 +62,12 @@ func rmCmd(c *cli.Context) error { if err != nil { return errors.Wrapf(err, "unable to get container list") } + } else if c.Bool("latest") { + lastCtr, err := runtime.GetLatestContainer() + if err != nil { + return errors.Wrapf(err, "unable to get latest container") + } + delContainers = append(delContainers, lastCtr) } else { for _, i := range args { container, err := runtime.LookupContainer(i) diff --git a/cmd/podman/start.go b/cmd/podman/start.go index d4ddfbbe7..0dad5e237 100644 --- a/cmd/podman/start.go +++ b/cmd/podman/start.go @@ -26,6 +26,7 @@ var ( Name: "interactive, i", Usage: "Keep STDIN open even if not attached", }, + LatestFlag, } startDescription = ` podman start @@ -46,7 +47,7 @@ var ( func startCmd(c *cli.Context) error { args := c.Args() - if len(args) < 1 { + if len(args) < 1 && !c.Bool("latest") { return errors.Errorf("you must provide at least one container name or id") } @@ -65,7 +66,13 @@ func startCmd(c *cli.Context) error { return errors.Wrapf(err, "error creating libpod runtime") } defer runtime.Shutdown(false) - + if c.Bool("latest") { + lastCtr, err := runtime.GetLatestContainer() + if err != nil { + return errors.Wrapf(err, "unable to get latest container") + } + args = append(args, lastCtr.ID()) + } var lastError error for _, container := range args { // Create a bool channel to track that the console socket attach diff --git a/cmd/podman/stats.go b/cmd/podman/stats.go index cf54a8bfe..d2ffd8a75 100644 --- a/cmd/podman/stats.go +++ b/cmd/podman/stats.go @@ -42,7 +42,7 @@ var ( cli.BoolFlag{ Name: "no-reset", Usage: "disable resetting the screen between intervals", - }, + }, LatestFlag, } statsDescription = "display a live stream of one or more containers' resource usage statistics" @@ -61,6 +61,15 @@ func statsCmd(c *cli.Context) error { return err } + all := c.Bool("all") + + if c.Bool("latest") && all { + return errors.Errorf("--all and --latest cannot be used together") + } + + if c.Bool("latest") && len(c.Args()) > 0 { + return errors.Errorf("no container names are allowed with --latest") + } runtime, err := getRuntime(c) if err != nil { return errors.Wrapf(err, "could not get runtime") @@ -75,7 +84,6 @@ func statsCmd(c *cli.Context) error { var format string var ctrs []*libpod.Container var containerFunc func() ([]*libpod.Container, error) - all := c.Bool("all") if c.IsSet("format") { format = c.String("format") @@ -85,6 +93,13 @@ func statsCmd(c *cli.Context) error { if len(c.Args()) > 0 { containerFunc = func() ([]*libpod.Container, error) { return runtime.GetContainersByList(c.Args()) } + } else if c.Bool("latest") { + containerFunc = func() ([]*libpod.Container, error) { + var ctrs []*libpod.Container + lastCtr, err := runtime.GetLatestContainer() + ctrs = append(ctrs, lastCtr) + return ctrs, err + } } else if all { containerFunc = runtime.GetAllContainers } else { diff --git a/cmd/podman/stop.go b/cmd/podman/stop.go index f85512d47..d18a05bd4 100644 --- a/cmd/podman/stop.go +++ b/cmd/podman/stop.go @@ -19,7 +19,7 @@ var ( cli.BoolFlag{ Name: "all, a", Usage: "stop all running containers", - }, + }, LatestFlag, } stopDescription = ` podman stop @@ -41,10 +41,13 @@ var ( func stopCmd(c *cli.Context) error { args := c.Args() - if c.Bool("all") && len(args) > 0 { - return errors.Errorf("no arguments are needed with -a") + if (c.Bool("all") || c.Bool("latest")) && len(args) > 0 { + return errors.Errorf("no arguments are needed with --all or --latest") + } + if c.Bool("all") && c.Bool("latest") { + return errors.Errorf("--all and --latest cannot be used together") } - if len(args) < 1 && !c.Bool("all") { + if len(args) < 1 && !c.Bool("all") && !c.Bool("latest") { return errors.Errorf("you must provide at least one container name or id") } if err := validateFlags(c, stopFlags); err != nil { @@ -71,6 +74,12 @@ func stopCmd(c *cli.Context) error { if err != nil { return errors.Wrapf(err, "unable to get running containers") } + } else if c.Bool("latest") { + lastCtr, err := runtime.GetLatestContainer() + if err != nil { + return errors.Wrapf(err, "unable to get last created container") + } + containers = append(containers, lastCtr) } else { for _, i := range args { container, err := runtime.LookupContainer(i) diff --git a/cmd/podman/top.go b/cmd/podman/top.go index 796b31c1d..5b1dbd05c 100644 --- a/cmd/podman/top.go +++ b/cmd/podman/top.go @@ -16,7 +16,7 @@ var ( cli.StringFlag{ Name: "format", Usage: "Change the output to JSON", - }, + }, LatestFlag, } topDescription = ` podman top @@ -36,6 +36,8 @@ var ( ) func topCmd(c *cli.Context) error { + var container *libpod.Container + var err error doJSON := false if c.IsSet("format") { if strings.ToUpper(c.String("format")) == "JSON" { @@ -47,7 +49,7 @@ func topCmd(c *cli.Context) error { args := c.Args() var psArgs []string psOpts := []string{"-o", "uid,pid,ppid,c,stime,tname,time,cmd"} - if len(args) < 1 { + if len(args) < 1 && !c.Bool("latest") { return errors.Errorf("you must provide the name or id of a running container") } if err := validateFlags(c, topFlags); err != nil { @@ -63,7 +65,12 @@ func topCmd(c *cli.Context) error { psOpts = args[1:] } - container, err := runtime.LookupContainer(args[0]) + if c.Bool("latest") { + container, err = runtime.GetLatestContainer() + } else { + container, err = runtime.LookupContainer(args[0]) + } + if err != nil { return errors.Wrapf(err, "unable to lookup %s", args[0]) } -- cgit v1.2.3-54-g00ecf