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 <bbaude@redhat.com>

Closes: #179
Approved by: baude
This commit is contained in:
baude
2018-01-02 16:29:43 -06:00
committed by Atomic Bot
parent 6baf6e461d
commit 7b08aa78e4
27 changed files with 257 additions and 48 deletions

View File

@ -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])

View File

@ -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) {

View File

@ -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])
}

View File

@ -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)
}

View File

@ -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,6 +17,7 @@ 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{
@ -26,15 +27,19 @@ var (
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 {

View File

@ -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
}

View File

@ -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)

View File

@ -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

View File

@ -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 {

View File

@ -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 len(args) < 1 && !c.Bool("all") {
if c.Bool("all") && c.Bool("latest") {
return errors.Errorf("--all and --latest cannot be used together")
}
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)

View File

@ -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])
}

View File

@ -653,7 +653,10 @@ _podman_attach() {
local boolean_options="
--help
-h
--no-stdin"
--latest
-l
--no-stdin
"
_complete_ "$options_with_args" "$boolean_options"
}
@ -752,6 +755,8 @@ _podman_exec() {
-u
"
local boolean_options="
--latest
-l
--privileged
--tty
-t
@ -875,6 +880,8 @@ _podman_inspect() {
local boolean_options="
--help
-h
--latest
-l
"
local options_with_args="
--format
@ -898,7 +905,10 @@ _podman_kill() {
"
local boolean_options="
--help
-h"
-h
--latest
-l
"
_complete_ "$options_with_args" "$boolean_options"
}
@ -910,6 +920,8 @@ _podman_logs() {
local boolean_options="
--follow
-f
--latest
-l
"
_complete_ "$options_with_args" "$boolean_options"
@ -1286,6 +1298,8 @@ _podman_rm() {
-a
--force
-f
--latest
-l
"
local options_with_args="
@ -1355,6 +1369,10 @@ podman_top() {
local options_with_args="
"
local boolean_options="
--help
-h
--latest
-l
"
_complete_ "$options_with_args" "$boolean_options"
}
@ -1424,7 +1442,9 @@ _podman_start() {
-a
--attach
-i
--interactive"
--interactive
--latest
-l"
_complete_ "$options_with_args" "$boolean_options"
}
_podman_stop() {
@ -1433,7 +1453,9 @@ _podman_stop() {
"
local boolean_options="
--all
-a"
-a
--latest
-l"
_complete_ "$options_with_args" "$boolean_options"
}

View File

@ -20,6 +20,10 @@ sequence is CTRL-p CTRL-q. You configure the key sequence using the --detach-key
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 _.
**--latest, -l**
Instead of providing the container name or ID, use the last created container. If you use methods other than Podman
to run containers such as CRI-O, the last started container could be from either of those methods.
**--no-stdin**
Do not attach STDIN. The default is false.
@ -30,6 +34,10 @@ podman attach foobar
[root@localhost /]#
```
```
podman attach --latest
[root@localhost /]#
```
```
podman attach 1234
[root@localhost /]#
```

View File

@ -22,6 +22,10 @@ command to be executed.
**--interactive, -i**
Not supported. All exec commands are interactive by default.
**--latest, -l**
Instead of providing the container name or ID, use the last created container. If you use methods other than Podman
to run containers such as CRI-O, the last started container could be from either of those methods.
**--privileged**
Give the process extended Linux capabilities when running the command in container.

View File

@ -21,6 +21,10 @@ Return data on items of the specified type. Type can be 'container', 'image' or
Format the output using the given Go template
**--latest, -l**
Instead of providing the container name or ID, use the last created container. If you use methods other than Podman
to run containers such as CRI-O, the last started container could be from either of those methods.
**--size**
Display the total file size if the type is a container

View File

@ -12,6 +12,9 @@ podman kill - Kills one or more containers with a signal
The main process inside each container specified will be sent SIGKILL, or any signal specified with option --signal.
## OPTIONS
**--latest, -l**
Instead of providing the container name or ID, use the last created container. If you use methods other than Podman
to run containers such as CRI-O, the last started container could be from either of those methods.
**--signal, s**
@ -26,6 +29,8 @@ podman kill 860a4b23
podman kill --signal TERM 860a4b23
podman kill --latest
## SEE ALSO
podman(1), podman-stop(1)

View File

@ -21,6 +21,9 @@ Force the removal of a running container
Remove all containers. Can be used in conjunction with -f as well.
**--latest, -l**
Instead of providing the container name or ID, use the last created container. If you use methods other than Podman
to run containers such as CRI-O, the last started container could be from either of those methods.
## EXAMPLE
podman rm mywebserver
@ -31,6 +34,8 @@ podman rm -f 860a4b23
podman rm -f -a
podman rm -f --latest
## SEE ALSO
podman(1), podman-rmi(1)

View File

@ -29,6 +29,9 @@ ctrl-<value> where <value> is one of: a-z, @, ^, [, , or _.
Attach container's STDIN. The default is false.
**--latest, -l**
Instead of providing the container name or ID, use the last created container. If you use methods other than Podman
to run containers such as CRI-O, the last started container could be from either of those methods.
## EXAMPLE
@ -38,6 +41,8 @@ podman start 860a4b23 5421ab4
podman start -i -a 860a4b23
podman start -i -l
## SEE ALSO
podman(1), podman-create(1)

View File

@ -17,6 +17,10 @@ Display a live stream of one or more containers' resource usage statistics
Show all containers. Only running containers are shown by default
**--latest, -l**
Instead of providing the container name or ID, use the last created container. If you use methods other than Podman
to run containers such as CRI-O, the last started container could be from either of those methods.
**--no-reset**
Do not clear the terminal/screen in between reporting intervals

View File

@ -23,6 +23,9 @@ Timeout to wait before forcibly stopping the container
Stop all running containers. This does not include paused containers.
**--latest, -l**
Instead of providing the container name or ID, use the last created container. If you use methods other than Podman
to run containers such as CRI-O, the last started container could be from either of those methods.
## EXAMPLE
@ -36,6 +39,8 @@ podman stop --timeout 2 860a4b23
podman stop -a
podman stop --latest
## SEE ALSO
podman(1), podman-rm(1)

View File

@ -21,6 +21,10 @@ Display the running process of the container. ps-OPTION can be any of the option
**--format**
Display the output in an alternate format. The only supported format is **JSON**.
**--latest, -l**
Instead of providing the container name or ID, use the last created container. If you use methods other than Podman
to run containers such as CRI-O, the last started container could be from either of those methods.
## EXAMPLES
```

View File

@ -3,6 +3,7 @@ package libpod
import (
"os"
"path/filepath"
"time"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
@ -204,7 +205,6 @@ func (r *Runtime) LookupContainer(idOrName string) (*Container, error) {
if !r.valid {
return nil, ErrRuntimeStopped
}
return r.state.LookupContainer(idOrName)
}
@ -268,3 +268,21 @@ func (r *Runtime) GetContainersByList(containers []string) ([]*Container, error)
}
return ctrs, nil
}
// GetLatestContainer returns a container object of the latest created container.
func (r *Runtime) GetLatestContainer() (*Container, error) {
var lastCreatedIndex int
var lastCreatedTime time.Time
ctrs, err := r.GetAllContainers()
if err != nil {
return nil, errors.Wrapf(err, "unable to find latest container")
}
for containerIndex, ctr := range ctrs {
createdTime := ctr.config.CreatedTime
if createdTime.After(lastCreatedTime) {
lastCreatedTime = createdTime
lastCreatedIndex = containerIndex
}
}
return ctrs[lastCreatedIndex], nil
}

View File

@ -28,3 +28,10 @@ function setup() {
echo "$output"
[ "$status" -eq 0 ]
}
@test "exec simple command using latest" {
${PODMAN_BINARY} ${PODMAN_OPTIONS} run -d -t ${ALPINE} sleep 60
run ${PODMAN_BINARY} ${PODMAN_OPTIONS} exec -l ls
echo "$output"
[ "$status" -eq 0 ]
}

View File

@ -45,8 +45,7 @@ function setup() {
run bash -c "${PODMAN_BINARY} ${PODMAN_OPTIONS} create ${BB} ls"
echo "$output"
[ "$status" -eq 0 ]
ctr_id="$output"
run bash -c "${PODMAN_BINARY} $PODMAN_OPTIONS inspect --size $ctr_id | python -m json.tool | grep SizeRootFs"
run bash -c "${PODMAN_BINARY} $PODMAN_OPTIONS inspect --size -l | python -m json.tool | grep SizeRootFs"
echo "$output"
[ "$status" -eq 0 ]
}

View File

@ -62,3 +62,10 @@ function setup() {
run bash -c "${PODMAN_BINARY} ${PODMAN_OPTIONS} ps --no-trunc"
[ "$status" -eq 0 ]
}
@test "kill the latest container run" {
${PODMAN_BINARY} ${PODMAN_OPTIONS} run -d ${ALPINE} sleep 9999
run bash -c "${PODMAN_BINARY} ${PODMAN_OPTIONS} kill -l"
echo "$output"
[ "$status" -eq 0 ]
}

View File

@ -42,11 +42,10 @@ function setup() {
run bash -c "${PODMAN_BINARY} ${PODMAN_OPTIONS} run -d $BB ls"
echo "$output"
[ "$status" -eq 0 ]
ctr_id="$output"
run bash -c "${PODMAN_BINARY} ${PODMAN_OPTIONS} logs --since 2017-08-07T10:10:09.056611202-04:00 $ctr_id"
run bash -c "${PODMAN_BINARY} ${PODMAN_OPTIONS} logs --since 2017-08-07T10:10:09.056611202-04:00 -l"
echo "$output"
[ "$status" -eq 0 ]
run bash -c "${PODMAN_BINARY} ${PODMAN_OPTIONS} rm $ctr_id"
run bash -c "${PODMAN_BINARY} ${PODMAN_OPTIONS} rm -l"
echo "$output"
[ "$status" -eq 0 ]
}

View File

@ -47,3 +47,10 @@ function setup() {
echo "$output"
[ "$status" -eq 0 ]
}
@test "stop a container with latest" {
${PODMAN_BINARY} ${PODMAN_OPTIONS} run -d ${ALPINE} sleep 9999
run bash -c "${PODMAN_BINARY} ${PODMAN_OPTIONS} stop -t 1 -l"
echo "$output"
[ "$status" -eq 0 ]
}