mirror of https://github.com/containers/podman.git
Implement podman-remote wait command and container subcommand
Signed-off-by: Jhon Honce <jhonce@redhat.com>
This commit is contained in:
parent
c6c0b54c36
commit
8a6758d5fd
10
API.md
10
API.md
|
@ -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 VolumesPrune() []string, []string](#VolumesPrune)
|
||||||
|
|
||||||
[func WaitContainer(name: string) int](#WaitContainer)
|
[func WaitContainer(name: string, interval: int) int](#WaitContainer)
|
||||||
|
|
||||||
[type BuildInfo](#BuildInfo)
|
[type BuildInfo](#BuildInfo)
|
||||||
|
|
||||||
|
@ -1013,10 +1013,10 @@ VolumesPrune removes unused volumes on the host
|
||||||
### <a name="WaitContainer"></a>func WaitContainer
|
### <a name="WaitContainer"></a>func WaitContainer
|
||||||
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
|
<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>
|
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 until the container stops. Upon stopping, the return
|
WaitContainer takes the name or ID of a container and waits the given interval in milliseconds until the container
|
||||||
code of the container is returned. If the container container cannot be found by ID or name,
|
stops. Upon stopping, the return code of the container is returned. If the container container cannot be found by ID
|
||||||
a [ContainerNotFound](#ContainerNotFound) error is returned.
|
or name, a [ContainerNotFound](#ContainerNotFound) error is returned.
|
||||||
## Types
|
## Types
|
||||||
### <a name="BuildInfo"></a>type BuildInfo
|
### <a name="BuildInfo"></a>type BuildInfo
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,6 @@ func getMainCommands() []*cobra.Command {
|
||||||
_topCommand,
|
_topCommand,
|
||||||
_umountCommand,
|
_umountCommand,
|
||||||
_unpauseCommand,
|
_unpauseCommand,
|
||||||
_waitCommand,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(_varlinkCommand.Use) > 0 {
|
if len(_varlinkCommand.Use) > 0 {
|
||||||
|
|
|
@ -52,6 +52,7 @@ var mainCommands = []*cobra.Command{
|
||||||
_stopCommand,
|
_stopCommand,
|
||||||
_tagCommand,
|
_tagCommand,
|
||||||
_versionCommand,
|
_versionCommand,
|
||||||
|
_waitCommand,
|
||||||
imageCommand.Command,
|
imageCommand.Command,
|
||||||
systemCommand.Command,
|
systemCommand.Command,
|
||||||
}
|
}
|
||||||
|
|
|
@ -617,10 +617,10 @@ method UnpauseContainer(name: string) -> (container: string)
|
||||||
# ~~~
|
# ~~~
|
||||||
method GetAttachSockets(name: string) -> (sockets: Sockets)
|
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
|
# WaitContainer takes the name or ID of a container and waits the given interval in milliseconds until the container
|
||||||
# code of the container is returned. If the container container cannot be found by ID or name,
|
# stops. Upon stopping, the return code of the container is returned. If the container container cannot be found by ID
|
||||||
# a [ContainerNotFound](#ContainerNotFound) error is returned.
|
# or name, a [ContainerNotFound](#ContainerNotFound) error is returned.
|
||||||
method WaitContainer(name: string) -> (exitcode: int)
|
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
|
# 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
|
# indicating whether to remove builtin volumes. Upon successful removal of the
|
||||||
|
|
|
@ -2,11 +2,11 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/containers/libpod/cmd/podman/cliconfig"
|
"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/pkg/errors"
|
||||||
"github.com/spf13/cobra"
|
"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")
|
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 {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "error creating libpod runtime")
|
return errors.Wrapf(err, "error creating runtime")
|
||||||
}
|
}
|
||||||
defer runtime.Shutdown(false)
|
defer runtime.Shutdown(false)
|
||||||
|
|
||||||
|
ok, failures, err := runtime.WaitOnContainers(getContext(), c, interval)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "could not get config")
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var lastError error
|
for _, id := range ok {
|
||||||
if c.Latest {
|
fmt.Println(id)
|
||||||
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 {
|
if len(failures) > 0 {
|
||||||
ctr, err := runtime.LookupContainer(container)
|
keys := reflect.ValueOf(failures).MapKeys()
|
||||||
if err != nil {
|
lastKey := keys[len(keys)-1].String()
|
||||||
return errors.Wrapf(err, "unable to find container %s", container)
|
lastErr := failures[lastKey]
|
||||||
}
|
delete(failures, lastKey)
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return lastError
|
for _, err := range failures {
|
||||||
|
outputError(err)
|
||||||
|
}
|
||||||
|
return lastErr
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,9 @@ package adapter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"strconv"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/containers/libpod/cmd/podman/cliconfig"
|
"github.com/containers/libpod/cmd/podman/cliconfig"
|
||||||
"github.com/containers/libpod/libpod"
|
"github.com/containers/libpod/libpod"
|
||||||
|
@ -103,3 +105,25 @@ func (r *LocalRuntime) KillContainers(ctx context.Context, cli *cliconfig.KillVa
|
||||||
}
|
}
|
||||||
return ok, failures, nil
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -6,7 +6,9 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"strconv"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/containers/libpod/cmd/podman/cliconfig"
|
"github.com/containers/libpod/cmd/podman/cliconfig"
|
||||||
"github.com/containers/libpod/cmd/podman/shared"
|
"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
|
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
|
// 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) {
|
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
|
// TODO If pod ps ever shows container's sizes, re-enable this code; otherwise it isn't needed
|
||||||
|
|
|
@ -360,17 +360,16 @@ func (i *LibpodAPI) UnpauseContainer(call iopodman.VarlinkCall, name string) err
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitContainer ...
|
// 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)
|
ctr, err := i.Runtime.LookupContainer(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return call.ReplyContainerNotFound(name, err.Error())
|
return call.ReplyContainerNotFound(name, err.Error())
|
||||||
}
|
}
|
||||||
exitCode, err := ctr.Wait()
|
exitCode, err := ctr.WaitWithInterval(time.Duration(interval))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return call.ReplyErrorOccurred(err.Error())
|
return call.ReplyErrorOccurred(err.Error())
|
||||||
}
|
}
|
||||||
return call.ReplyWaitContainer(int64(exitCode))
|
return call.ReplyWaitContainer(int64(exitCode))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveContainer ...
|
// RemoveContainer ...
|
||||||
|
|
Loading…
Reference in New Issue