Merge pull request #2534 from jwhonce/wip/remote_wait

Implement podman-remote wait command and container subcommand
This commit is contained in:
OpenShift Merge Robot 2019-03-06 13:07:52 -08:00 committed by GitHub
commit 614409f644
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
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

@ -621,10 +621,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 c.Interval == 0 {
return errors.Errorf("interval must be greater then 0")
}
interval := time.Duration(c.Interval) * time.Millisecond
runtime, err := adapter.GetRuntime(&c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
return errors.Wrapf(err, "error creating runtime")
}
defer runtime.Shutdown(false)
ok, failures, err := runtime.WaitOnContainers(getContext(), c, interval)
if err != nil {
return errors.Wrapf(err, "could not get config")
return err
}
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 _, id := range ok {
fmt.Println(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)
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)
}
}
if len(failures) > 0 {
keys := reflect.ValueOf(failures).MapKeys()
lastKey := keys[len(keys)-1].String()
lastErr := failures[lastKey]
delete(failures, lastKey)
return lastError
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 ...