Implement podman-remote wait command and container subcommand

Signed-off-by: Jhon Honce <jhonce@redhat.com>
This commit is contained in:
Jhon Honce 2019-03-04 17:21:23 -07:00
parent c6c0b54c36
commit 8a6758d5fd
8 changed files with 86 additions and 44 deletions

10
API.md
View File

@ -143,7 +143,7 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[func VolumesPrune() []string, []string](#VolumesPrune)
[func WaitContainer(name: string) int](#WaitContainer)
[func WaitContainer(name: string, interval: int) int](#WaitContainer)
[type BuildInfo](#BuildInfo)
@ -1013,10 +1013,10 @@ VolumesPrune removes unused volumes on the host
### <a name="WaitContainer"></a>func WaitContainer
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
method WaitContainer(name: [string](https://godoc.org/builtin#string)) [int](https://godoc.org/builtin#int)</div>
WaitContainer takes the name or ID of a container and waits until the container stops. Upon stopping, the return
code of the container is returned. If the container container cannot be found by ID or name,
a [ContainerNotFound](#ContainerNotFound) error is returned.
method WaitContainer(name: [string](https://godoc.org/builtin#string), interval: [int](https://godoc.org/builtin#int)) [int](https://godoc.org/builtin#int)</div>
WaitContainer takes the name or ID of a container and waits the given interval in milliseconds until the container
stops. Upon stopping, the return code of the container is returned. If the container container cannot be found by ID
or name, a [ContainerNotFound](#ContainerNotFound) error is returned.
## Types
### <a name="BuildInfo"></a>type BuildInfo

View File

@ -35,7 +35,6 @@ func getMainCommands() []*cobra.Command {
_topCommand,
_umountCommand,
_unpauseCommand,
_waitCommand,
}
if len(_varlinkCommand.Use) > 0 {

View File

@ -52,6 +52,7 @@ var mainCommands = []*cobra.Command{
_stopCommand,
_tagCommand,
_versionCommand,
_waitCommand,
imageCommand.Command,
systemCommand.Command,
}

View File

@ -617,10 +617,10 @@ method UnpauseContainer(name: string) -> (container: string)
# ~~~
method GetAttachSockets(name: string) -> (sockets: Sockets)
# WaitContainer takes the name or ID of a container and waits until the container stops. Upon stopping, the return
# code of the container is returned. If the container container cannot be found by ID or name,
# a [ContainerNotFound](#ContainerNotFound) error is returned.
method WaitContainer(name: string) -> (exitcode: int)
# WaitContainer takes the name or ID of a container and waits the given interval in milliseconds until the container
# stops. Upon stopping, the return code of the container is returned. If the container container cannot be found by ID
# or name, a [ContainerNotFound](#ContainerNotFound) error is returned.
method WaitContainer(name: string, interval: int) -> (exitcode: int)
# RemoveContainer requires the name or ID of container as well a boolean representing whether a running container can be stopped and removed, and a boolean
# indicating whether to remove builtin volumes. Upon successful removal of the

View File

@ -2,11 +2,11 @@ package main
import (
"fmt"
"os"
"reflect"
"time"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/pkg/adapter"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@ -49,43 +49,36 @@ func waitCmd(c *cliconfig.WaitValues) error {
return errors.Errorf("you must provide at least one container name or id")
}
runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
defer runtime.Shutdown(false)
if err != nil {
return errors.Wrapf(err, "could not get config")
}
var lastError error
if c.Latest {
latestCtr, err := runtime.GetLatestContainer()
if err != nil {
return errors.Wrapf(err, "unable to wait on latest container")
}
args = append(args, latestCtr.ID())
}
for _, container := range args {
ctr, err := runtime.LookupContainer(container)
if err != nil {
return errors.Wrapf(err, "unable to find container %s", container)
}
if c.Interval == 0 {
return errors.Errorf("interval must be greater then 0")
}
returnCode, err := ctr.WaitWithInterval(time.Duration(c.Interval) * time.Millisecond)
interval := time.Duration(c.Interval) * time.Millisecond
runtime, err := adapter.GetRuntime(&c.PodmanCommand)
if err != nil {
if lastError != nil {
fmt.Fprintln(os.Stderr, lastError)
}
lastError = errors.Wrapf(err, "failed to wait for the container %v", container)
} else {
fmt.Println(returnCode)
return errors.Wrapf(err, "error creating runtime")
}
defer runtime.Shutdown(false)
ok, failures, err := runtime.WaitOnContainers(getContext(), c, interval)
if err != nil {
return err
}
return lastError
for _, id := range ok {
fmt.Println(id)
}
if len(failures) > 0 {
keys := reflect.ValueOf(failures).MapKeys()
lastKey := keys[len(keys)-1].String()
lastErr := failures[lastKey]
delete(failures, lastKey)
for _, err := range failures {
outputError(err)
}
return lastErr
}
return nil
}

View File

@ -4,7 +4,9 @@ package adapter
import (
"context"
"strconv"
"syscall"
"time"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/libpod"
@ -103,3 +105,25 @@ func (r *LocalRuntime) KillContainers(ctx context.Context, cli *cliconfig.KillVa
}
return ok, failures, nil
}
// WaitOnContainers waits for all given container(s) to stop
func (r *LocalRuntime) WaitOnContainers(ctx context.Context, cli *cliconfig.WaitValues, interval time.Duration) ([]string, map[string]error, error) {
var (
ok = []string{}
failures = map[string]error{}
)
ctrs, err := shortcuts.GetContainersByContext(false, cli.Latest, cli.InputArgs, r.Runtime)
if err != nil {
return ok, failures, err
}
for _, c := range ctrs {
if returnCode, err := c.WaitWithInterval(interval); err == nil {
ok = append(ok, strconv.Itoa(int(returnCode)))
} else {
failures[c.ID()] = err
}
}
return ok, failures, err
}

View File

@ -6,7 +6,9 @@ import (
"context"
"encoding/json"
"errors"
"strconv"
"syscall"
"time"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/shared"
@ -173,6 +175,30 @@ func (r *LocalRuntime) KillContainers(ctx context.Context, cli *cliconfig.KillVa
return ok, failures, nil
}
// WaitOnContainers waits for all given container(s) to stop.
// interval is currently ignored.
func (r *LocalRuntime) WaitOnContainers(ctx context.Context, cli *cliconfig.WaitValues, interval time.Duration) ([]string, map[string]error, error) {
var (
ok = []string{}
failures = map[string]error{}
)
ids, err := iopodman.GetContainersByContext().Call(r.Conn, false, cli.Latest, cli.InputArgs)
if err != nil {
return ok, failures, err
}
for _, id := range ids {
stopped, err := iopodman.WaitContainer().Call(r.Conn, id, int64(interval))
if err != nil {
failures[id] = err
} else {
ok = append(ok, strconv.FormatInt(stopped, 10))
}
}
return ok, failures, nil
}
// BatchContainerOp is wrapper func to mimic shared's function with a similar name meant for libpod
func BatchContainerOp(ctr *Container, opts shared.PsOptions) (shared.BatchContainerStruct, error) {
// TODO If pod ps ever shows container's sizes, re-enable this code; otherwise it isn't needed

View File

@ -360,17 +360,16 @@ func (i *LibpodAPI) UnpauseContainer(call iopodman.VarlinkCall, name string) err
}
// WaitContainer ...
func (i *LibpodAPI) WaitContainer(call iopodman.VarlinkCall, name string) error {
func (i *LibpodAPI) WaitContainer(call iopodman.VarlinkCall, name string, interval int64) error {
ctr, err := i.Runtime.LookupContainer(name)
if err != nil {
return call.ReplyContainerNotFound(name, err.Error())
}
exitCode, err := ctr.Wait()
exitCode, err := ctr.WaitWithInterval(time.Duration(interval))
if err != nil {
return call.ReplyErrorOccurred(err.Error())
}
return call.ReplyWaitContainer(int64(exitCode))
}
// RemoveContainer ...