mirror of
https://github.com/containers/podman.git
synced 2025-07-04 10:10:32 +08:00
Switch podman stop/kill/wait handlers to use abi
Change API Handlers to use the same functions that the local podman uses. At the same time: implement remote API for --all and --ignore flags for podman stop implement remote API for --all flags for podman stop Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
@ -2,8 +2,9 @@ package containers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/containers/common/pkg/completion"
|
"github.com/containers/common/pkg/completion"
|
||||||
"github.com/containers/podman/v2/cmd/podman/common"
|
"github.com/containers/podman/v2/cmd/podman/common"
|
||||||
@ -12,6 +13,7 @@ import (
|
|||||||
"github.com/containers/podman/v2/cmd/podman/validate"
|
"github.com/containers/podman/v2/cmd/podman/validate"
|
||||||
"github.com/containers/podman/v2/pkg/domain/entities"
|
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v2/pkg/signal"
|
"github.com/containers/podman/v2/pkg/signal"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -59,7 +61,7 @@ func killFlags(cmd *cobra.Command) {
|
|||||||
flags.StringVarP(&killOptions.Signal, signalFlagName, "s", "KILL", "Signal to send to the container")
|
flags.StringVarP(&killOptions.Signal, signalFlagName, "s", "KILL", "Signal to send to the container")
|
||||||
_ = cmd.RegisterFlagCompletionFunc(signalFlagName, common.AutocompleteStopSignal)
|
_ = cmd.RegisterFlagCompletionFunc(signalFlagName, common.AutocompleteStopSignal)
|
||||||
cidfileFlagName := "cidfile"
|
cidfileFlagName := "cidfile"
|
||||||
flags.StringArrayVar(&killOptions.CIDFiles, cidfileFlagName, []string{}, "Read the container ID from the file")
|
flags.StringArrayVar(&cidFiles, cidfileFlagName, []string{}, "Read the container ID from the file")
|
||||||
_ = cmd.RegisterFlagCompletionFunc(cidfileFlagName, completion.AutocompleteDefault)
|
_ = cmd.RegisterFlagCompletionFunc(cidfileFlagName, completion.AutocompleteDefault)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,6 +96,15 @@ func kill(_ *cobra.Command, args []string) error {
|
|||||||
if sig < 1 || sig > 64 {
|
if sig < 1 || sig > 64 {
|
||||||
return errors.New("valid signals are 1 through 64")
|
return errors.New("valid signals are 1 through 64")
|
||||||
}
|
}
|
||||||
|
for _, cidFile := range cidFiles {
|
||||||
|
content, err := ioutil.ReadFile(string(cidFile))
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "error reading CIDFile")
|
||||||
|
}
|
||||||
|
id := strings.Split(string(content), "\n")[0]
|
||||||
|
args = append(args, id)
|
||||||
|
}
|
||||||
|
|
||||||
responses, err := registry.ContainerEngine().ContainerKill(context.Background(), args, killOptions)
|
responses, err := registry.ContainerEngine().ContainerKill(context.Background(), args, killOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -3,6 +3,8 @@ package containers
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/containers/common/pkg/completion"
|
"github.com/containers/common/pkg/completion"
|
||||||
"github.com/containers/podman/v2/cmd/podman/common"
|
"github.com/containers/podman/v2/cmd/podman/common"
|
||||||
@ -10,6 +12,7 @@ import (
|
|||||||
"github.com/containers/podman/v2/cmd/podman/utils"
|
"github.com/containers/podman/v2/cmd/podman/utils"
|
||||||
"github.com/containers/podman/v2/cmd/podman/validate"
|
"github.com/containers/podman/v2/cmd/podman/validate"
|
||||||
"github.com/containers/podman/v2/pkg/domain/entities"
|
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -58,7 +61,7 @@ func stopFlags(cmd *cobra.Command) {
|
|||||||
flags.BoolVarP(&stopOptions.Ignore, "ignore", "i", false, "Ignore errors when a specified container is missing")
|
flags.BoolVarP(&stopOptions.Ignore, "ignore", "i", false, "Ignore errors when a specified container is missing")
|
||||||
|
|
||||||
cidfileFlagName := "cidfile"
|
cidfileFlagName := "cidfile"
|
||||||
flags.StringArrayVarP(&stopOptions.CIDFiles, cidfileFlagName, "", nil, "Read the container ID from the file")
|
flags.StringArrayVar(&cidFiles, cidfileFlagName, nil, "Read the container ID from the file")
|
||||||
_ = cmd.RegisterFlagCompletionFunc(cidfileFlagName, completion.AutocompleteDefault)
|
_ = cmd.RegisterFlagCompletionFunc(cidfileFlagName, completion.AutocompleteDefault)
|
||||||
|
|
||||||
timeFlagName := "time"
|
timeFlagName := "time"
|
||||||
@ -97,6 +100,15 @@ func stop(cmd *cobra.Command, args []string) error {
|
|||||||
stopOptions.Timeout = &stopTimeout
|
stopOptions.Timeout = &stopTimeout
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, cidFile := range cidFiles {
|
||||||
|
content, err := ioutil.ReadFile(string(cidFile))
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "error reading CIDFile")
|
||||||
|
}
|
||||||
|
id := strings.Split(string(content), "\n")[0]
|
||||||
|
args = append(args, id)
|
||||||
|
}
|
||||||
|
|
||||||
responses, err := registry.ContainerEngine().ContainerStop(context.Background(), args, stopOptions)
|
responses, err := registry.ContainerEngine().ContainerStop(context.Background(), args, stopOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -50,7 +50,7 @@ func waitFlags(cmd *cobra.Command) {
|
|||||||
flags := cmd.Flags()
|
flags := cmd.Flags()
|
||||||
|
|
||||||
intervalFlagName := "interval"
|
intervalFlagName := "interval"
|
||||||
flags.StringVarP(&waitInterval, intervalFlagName, "i", "250ns", "Time Interval to wait before polling for completion")
|
flags.StringVarP(&waitInterval, intervalFlagName, "i", "250ms", "Time Interval to wait before polling for completion")
|
||||||
_ = cmd.RegisterFlagCompletionFunc(intervalFlagName, completion.AutocompleteNone)
|
_ = cmd.RegisterFlagCompletionFunc(intervalFlagName, completion.AutocompleteNone)
|
||||||
|
|
||||||
conditionFlagName := "condition"
|
conditionFlagName := "condition"
|
||||||
|
@ -31,11 +31,11 @@ import (
|
|||||||
func RemoveContainer(w http.ResponseWriter, r *http.Request) {
|
func RemoveContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
||||||
query := struct {
|
query := struct {
|
||||||
All bool `schema:"all"`
|
Force bool `schema:"force"`
|
||||||
Force bool `schema:"force"`
|
Ignore bool `schema:"ignore"`
|
||||||
Ignore bool `schema:"ignore"`
|
Link bool `schema:"link"`
|
||||||
Link bool `schema:"link"`
|
DockerVolumes bool `schema:"v"`
|
||||||
Volumes bool `schema:"v"`
|
LibpodVolumes bool `schema:"volumes"`
|
||||||
}{
|
}{
|
||||||
// override any golang type defaults
|
// override any golang type defaults
|
||||||
}
|
}
|
||||||
@ -46,10 +46,19 @@ func RemoveContainer(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if query.Link && !utils.IsLibpodRequest(r) {
|
options := entities.RmOptions{
|
||||||
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
|
Force: query.Force,
|
||||||
utils.ErrLinkNotSupport)
|
Ignore: query.Ignore,
|
||||||
return
|
}
|
||||||
|
if utils.IsLibpodRequest(r) {
|
||||||
|
options.Volumes = query.LibpodVolumes
|
||||||
|
} else {
|
||||||
|
if query.Link {
|
||||||
|
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
|
||||||
|
utils.ErrLinkNotSupport)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
options.Volumes = query.DockerVolumes
|
||||||
}
|
}
|
||||||
|
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
||||||
@ -57,12 +66,6 @@ func RemoveContainer(w http.ResponseWriter, r *http.Request) {
|
|||||||
// code.
|
// code.
|
||||||
containerEngine := abi.ContainerEngine{Libpod: runtime}
|
containerEngine := abi.ContainerEngine{Libpod: runtime}
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
options := entities.RmOptions{
|
|
||||||
All: query.All,
|
|
||||||
Force: query.Force,
|
|
||||||
Volumes: query.Volumes,
|
|
||||||
Ignore: query.Ignore,
|
|
||||||
}
|
|
||||||
report, err := containerEngine.ContainerRm(r.Context(), []string{name}, options)
|
report, err := containerEngine.ContainerRm(r.Context(), []string{name}, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Cause(err) == define.ErrNoSuchCtr {
|
if errors.Cause(err) == define.ErrNoSuchCtr {
|
||||||
@ -193,45 +196,48 @@ func KillContainer(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
sig, err := signal.ParseSignalNameOrNumber(query.Signal)
|
// Now use the ABI implementation to prevent us from having duplicate
|
||||||
if err != nil {
|
// code.
|
||||||
utils.InternalServerError(w, err)
|
containerEngine := abi.ContainerEngine{Libpod: runtime}
|
||||||
return
|
|
||||||
}
|
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
con, err := runtime.LookupContainer(name)
|
options := entities.KillOptions{
|
||||||
if err != nil {
|
Signal: query.Signal,
|
||||||
utils.ContainerNotFound(w, name, err)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
report, err := containerEngine.ContainerKill(r.Context(), []string{name}, options)
|
||||||
state, err := con.State()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Cause(err) == define.ErrCtrStateInvalid ||
|
||||||
|
errors.Cause(err) == define.ErrCtrStopped {
|
||||||
|
utils.Error(w, fmt.Sprintf("Container %s is not running", name), http.StatusConflict, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if errors.Cause(err) == define.ErrNoSuchCtr {
|
||||||
|
utils.ContainerNotFound(w, name, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
utils.InternalServerError(w, err)
|
utils.InternalServerError(w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the Container is stopped already, send a 409
|
if len(report) > 0 && report[0].Err != nil {
|
||||||
if state == define.ContainerStateStopped || state == define.ContainerStateExited {
|
utils.InternalServerError(w, report[0].Err)
|
||||||
utils.Error(w, fmt.Sprintf("Container %s is not running", name), http.StatusConflict, errors.New(fmt.Sprintf("Cannot kill Container %s, it is not running", name)))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
signal := uint(sig)
|
|
||||||
|
|
||||||
err = con.Kill(signal)
|
|
||||||
if err != nil {
|
|
||||||
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "unable to kill Container %s", name))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Docker waits for the container to stop if the signal is 0 or
|
// Docker waits for the container to stop if the signal is 0 or
|
||||||
// SIGKILL.
|
// SIGKILL.
|
||||||
if !utils.IsLibpodRequest(r) && (signal == 0 || syscall.Signal(signal) == syscall.SIGKILL) {
|
if !utils.IsLibpodRequest(r) {
|
||||||
if _, err = con.Wait(); err != nil {
|
sig, err := signal.ParseSignalNameOrNumber(query.Signal)
|
||||||
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "failed to wait for Container %s", con.ID()))
|
if err != nil {
|
||||||
|
utils.InternalServerError(w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if sig == 0 || syscall.Signal(sig) == syscall.SIGKILL {
|
||||||
|
var opts entities.WaitOptions
|
||||||
|
if _, err := containerEngine.ContainerWait(r.Context(), []string{name}, opts); err != nil {
|
||||||
|
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Success
|
// Success
|
||||||
utils.WriteResponse(w, http.StatusNoContent, nil)
|
utils.WriteResponse(w, http.StatusNoContent, nil)
|
||||||
@ -242,6 +248,10 @@ func WaitContainer(w http.ResponseWriter, r *http.Request) {
|
|||||||
// /{version}/containers/(name)/wait
|
// /{version}/containers/(name)/wait
|
||||||
exitCode, err := utils.WaitContainer(w, r)
|
exitCode, err := utils.WaitContainer(w, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Cause(err) == define.ErrNoSuchCtr {
|
||||||
|
logrus.Warnf("container not found %q: %v", utils.GetName(r), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
logrus.Warnf("failed to wait on container %q: %v", mux.Vars(r)["name"], err)
|
logrus.Warnf("failed to wait on container %q: %v", mux.Vars(r)["name"], err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,10 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/containers/podman/v2/libpod"
|
"github.com/containers/podman/v2/libpod"
|
||||||
|
"github.com/containers/podman/v2/libpod/define"
|
||||||
"github.com/containers/podman/v2/pkg/api/handlers/utils"
|
"github.com/containers/podman/v2/pkg/api/handlers/utils"
|
||||||
|
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||||
|
"github.com/containers/podman/v2/pkg/domain/infra/abi"
|
||||||
"github.com/gorilla/schema"
|
"github.com/gorilla/schema"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
@ -12,31 +15,46 @@ import (
|
|||||||
func RestartContainer(w http.ResponseWriter, r *http.Request) {
|
func RestartContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
||||||
|
// Now use the ABI implementation to prevent us from having duplicate
|
||||||
|
// code.
|
||||||
|
containerEngine := abi.ContainerEngine{Libpod: runtime}
|
||||||
|
|
||||||
// /{version}/containers/(name)/restart
|
// /{version}/containers/(name)/restart
|
||||||
query := struct {
|
query := struct {
|
||||||
Timeout int `schema:"t"`
|
All bool `schema:"all"`
|
||||||
|
DockerTimeout uint `schema:"t"`
|
||||||
|
LibpodTimeout uint `schema:"timeout"`
|
||||||
}{
|
}{
|
||||||
// Override golang default values for types
|
// override any golang type defaults
|
||||||
}
|
}
|
||||||
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
|
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
|
||||||
utils.BadRequest(w, "url", r.URL.String(), errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
|
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
|
||||||
|
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
con, err := runtime.LookupContainer(name)
|
|
||||||
|
options := entities.RestartOptions{
|
||||||
|
All: query.All,
|
||||||
|
Timeout: &query.DockerTimeout,
|
||||||
|
}
|
||||||
|
if utils.IsLibpodRequest(r) {
|
||||||
|
options.Timeout = &query.LibpodTimeout
|
||||||
|
}
|
||||||
|
report, err := containerEngine.ContainerRestart(r.Context(), []string{name}, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.ContainerNotFound(w, name, err)
|
if errors.Cause(err) == define.ErrNoSuchCtr {
|
||||||
|
utils.ContainerNotFound(w, name, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
utils.InternalServerError(w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
timeout := con.StopTimeout()
|
if len(report) > 0 && report[0].Err != nil {
|
||||||
if _, found := r.URL.Query()["t"]; found {
|
utils.InternalServerError(w, report[0].Err)
|
||||||
timeout = uint(query.Timeout)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := con.RestartWithTimeout(r.Context(), timeout); err != nil {
|
|
||||||
utils.InternalServerError(w, err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,8 @@ import (
|
|||||||
"github.com/containers/podman/v2/libpod"
|
"github.com/containers/podman/v2/libpod"
|
||||||
"github.com/containers/podman/v2/libpod/define"
|
"github.com/containers/podman/v2/libpod/define"
|
||||||
"github.com/containers/podman/v2/pkg/api/handlers/utils"
|
"github.com/containers/podman/v2/pkg/api/handlers/utils"
|
||||||
|
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||||
|
"github.com/containers/podman/v2/pkg/domain/infra/abi"
|
||||||
"github.com/gorilla/schema"
|
"github.com/gorilla/schema"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
@ -13,10 +15,15 @@ import (
|
|||||||
func StopContainer(w http.ResponseWriter, r *http.Request) {
|
func StopContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
||||||
|
// Now use the ABI implementation to prevent us from having duplicate
|
||||||
|
// code.
|
||||||
|
containerEngine := abi.ContainerEngine{Libpod: runtime}
|
||||||
|
|
||||||
// /{version}/containers/(name)/stop
|
// /{version}/containers/(name)/stop
|
||||||
query := struct {
|
query := struct {
|
||||||
Timeout int `schema:"t"`
|
Ignore bool `schema:"ignore"`
|
||||||
|
DockerTimeout uint `schema:"t"`
|
||||||
|
LibpodTimeout uint `schema:"timeout"`
|
||||||
}{
|
}{
|
||||||
// override any golang type defaults
|
// override any golang type defaults
|
||||||
}
|
}
|
||||||
@ -27,31 +34,46 @@ func StopContainer(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
|
|
||||||
|
options := entities.StopOptions{
|
||||||
|
Ignore: query.Ignore,
|
||||||
|
}
|
||||||
|
if utils.IsLibpodRequest(r) {
|
||||||
|
if query.LibpodTimeout > 0 {
|
||||||
|
options.Timeout = &query.LibpodTimeout
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if query.DockerTimeout > 0 {
|
||||||
|
options.Timeout = &query.DockerTimeout
|
||||||
|
}
|
||||||
|
}
|
||||||
con, err := runtime.LookupContainer(name)
|
con, err := runtime.LookupContainer(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.ContainerNotFound(w, name, err)
|
utils.ContainerNotFound(w, name, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
state, err := con.State()
|
state, err := con.State()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.InternalServerError(w, errors.Wrapf(err, "unable to get state for Container %s", name))
|
utils.InternalServerError(w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// If the Container is stopped already, send a 304
|
|
||||||
if state == define.ContainerStateStopped || state == define.ContainerStateExited {
|
if state == define.ContainerStateStopped || state == define.ContainerStateExited {
|
||||||
utils.WriteResponse(w, http.StatusNotModified, nil)
|
utils.WriteResponse(w, http.StatusNotModified, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
report, err := containerEngine.ContainerStop(r.Context(), []string{name}, options)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Cause(err) == define.ErrNoSuchCtr {
|
||||||
|
utils.ContainerNotFound(w, name, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var stopError error
|
utils.InternalServerError(w, err)
|
||||||
if query.Timeout > 0 {
|
return
|
||||||
stopError = con.StopWithTimeout(uint(query.Timeout))
|
|
||||||
} else {
|
|
||||||
stopError = con.Stop()
|
|
||||||
}
|
}
|
||||||
if stopError != nil {
|
|
||||||
utils.InternalServerError(w, errors.Wrapf(stopError, "failed to stop %s", name))
|
if len(report) > 0 && report[0].Err != nil {
|
||||||
|
utils.InternalServerError(w, report[0].Err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,6 +148,12 @@ func GetContainer(w http.ResponseWriter, r *http.Request) {
|
|||||||
func WaitContainer(w http.ResponseWriter, r *http.Request) {
|
func WaitContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
exitCode, err := utils.WaitContainer(w, r)
|
exitCode, err := utils.WaitContainer(w, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
name := utils.GetName(r)
|
||||||
|
if errors.Cause(err) == define.ErrNoSuchCtr {
|
||||||
|
utils.ContainerNotFound(w, name, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logrus.Warnf("failed to wait on container %q: %v", name, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
utils.WriteResponse(w, http.StatusOK, strconv.Itoa(int(exitCode)))
|
utils.WriteResponse(w, http.StatusOK, strconv.Itoa(int(exitCode)))
|
||||||
|
@ -6,6 +6,8 @@ import (
|
|||||||
|
|
||||||
"github.com/containers/podman/v2/libpod"
|
"github.com/containers/podman/v2/libpod"
|
||||||
"github.com/containers/podman/v2/libpod/define"
|
"github.com/containers/podman/v2/libpod/define"
|
||||||
|
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||||
|
"github.com/containers/podman/v2/pkg/domain/infra/abi"
|
||||||
"github.com/gorilla/schema"
|
"github.com/gorilla/schema"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
@ -16,10 +18,13 @@ func WaitContainer(w http.ResponseWriter, r *http.Request) (int32, error) {
|
|||||||
interval time.Duration
|
interval time.Duration
|
||||||
)
|
)
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
||||||
|
// Now use the ABI implementation to prevent us from having duplicate
|
||||||
|
// code.
|
||||||
|
containerEngine := abi.ContainerEngine{Libpod: runtime}
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
||||||
query := struct {
|
query := struct {
|
||||||
Interval string `schema:"interval"`
|
Interval string `schema:"interval"`
|
||||||
Condition string `schema:"condition"`
|
Condition define.ContainerStatus `schema:"condition"`
|
||||||
}{
|
}{
|
||||||
// Override golang default values for types
|
// Override golang default values for types
|
||||||
}
|
}
|
||||||
@ -27,6 +32,10 @@ func WaitContainer(w http.ResponseWriter, r *http.Request) (int32, error) {
|
|||||||
Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
|
Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
options := entities.WaitOptions{
|
||||||
|
Condition: define.ContainerStateStopped,
|
||||||
|
}
|
||||||
|
name := GetName(r)
|
||||||
if _, found := r.URL.Query()["interval"]; found {
|
if _, found := r.URL.Query()["interval"]; found {
|
||||||
interval, err = time.ParseDuration(query.Interval)
|
interval, err = time.ParseDuration(query.Interval)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -40,19 +49,19 @@ func WaitContainer(w http.ResponseWriter, r *http.Request) (int32, error) {
|
|||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
condition := define.ContainerStateStopped
|
options.Interval = interval
|
||||||
|
|
||||||
if _, found := r.URL.Query()["condition"]; found {
|
if _, found := r.URL.Query()["condition"]; found {
|
||||||
condition, err = define.StringToContainerStatus(query.Condition)
|
options.Condition = query.Condition
|
||||||
if err != nil {
|
|
||||||
InternalServerError(w, err)
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
name := GetName(r)
|
|
||||||
con, err := runtime.LookupContainer(name)
|
report, err := containerEngine.ContainerWait(r.Context(), []string{name}, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ContainerNotFound(w, name, err)
|
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
return con.WaitForConditionWithInterval(interval, condition)
|
if len(report) == 0 {
|
||||||
|
InternalServerError(w, errors.New("No reports returned"))
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return report[0].ExitCode, report[0].Error
|
||||||
}
|
}
|
||||||
|
@ -199,6 +199,11 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error {
|
|||||||
// required: true
|
// required: true
|
||||||
// description: the name or ID of the container
|
// description: the name or ID of the container
|
||||||
// - in: query
|
// - in: query
|
||||||
|
// name: all
|
||||||
|
// type: boolean
|
||||||
|
// default: false
|
||||||
|
// description: Send kill signal to all containers
|
||||||
|
// - in: query
|
||||||
// name: signal
|
// name: signal
|
||||||
// type: string
|
// type: string
|
||||||
// default: TERM
|
// default: TERM
|
||||||
@ -486,6 +491,11 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error {
|
|||||||
// - paused
|
// - paused
|
||||||
// - running
|
// - running
|
||||||
// - stopped
|
// - stopped
|
||||||
|
// - in: query
|
||||||
|
// name: interval
|
||||||
|
// type: string
|
||||||
|
// default: "250ms"
|
||||||
|
// description: Time Interval to wait before polling for completion.
|
||||||
// produces:
|
// produces:
|
||||||
// - application/json
|
// - application/json
|
||||||
// responses:
|
// responses:
|
||||||
@ -1219,9 +1229,20 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error {
|
|||||||
// required: true
|
// required: true
|
||||||
// description: the name or ID of the container
|
// description: the name or ID of the container
|
||||||
// - in: query
|
// - in: query
|
||||||
// name: t
|
// name: all
|
||||||
|
// type: boolean
|
||||||
|
// default: false
|
||||||
|
// description: Stop all containers
|
||||||
|
// - in: query
|
||||||
|
// name: timeout
|
||||||
// type: integer
|
// type: integer
|
||||||
|
// default: 10
|
||||||
// description: number of seconds to wait before killing container
|
// description: number of seconds to wait before killing container
|
||||||
|
// - in: query
|
||||||
|
// name: Ignore
|
||||||
|
// type: boolean
|
||||||
|
// default: false
|
||||||
|
// description: do not return error if container is already stopped
|
||||||
// produces:
|
// produces:
|
||||||
// - application/json
|
// - application/json
|
||||||
// responses:
|
// responses:
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/containers/podman/v2/libpod/define"
|
"github.com/containers/podman/v2/libpod/define"
|
||||||
@ -83,18 +82,9 @@ func Remove(ctx context.Context, nameOrID string, options *RemoveOptions) error
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
params := url.Values{}
|
params, err := options.ToParams()
|
||||||
if v := options.GetVolumes(); options.Changed("Volumes") {
|
if err != nil {
|
||||||
params.Set("v", strconv.FormatBool(v))
|
return err
|
||||||
}
|
|
||||||
if all := options.GetAll(); options.Changed("All") {
|
|
||||||
params.Set("all", strconv.FormatBool(all))
|
|
||||||
}
|
|
||||||
if force := options.GetForce(); options.Changed("Force") {
|
|
||||||
params.Set("force", strconv.FormatBool(force))
|
|
||||||
}
|
|
||||||
if ignore := options.GetIgnore(); options.Changed("Ignore") {
|
|
||||||
params.Set("ignore", strconv.FormatBool(ignore))
|
|
||||||
}
|
}
|
||||||
response, err := conn.DoRequest(nil, http.MethodDelete, "/containers/%s", params, nil, nameOrID)
|
response, err := conn.DoRequest(nil, http.MethodDelete, "/containers/%s", params, nil, nameOrID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -130,7 +120,7 @@ func Inspect(ctx context.Context, nameOrID string, options *InspectOptions) (*de
|
|||||||
// Kill sends a given signal to a given container. The signal should be the string
|
// Kill sends a given signal to a given container. The signal should be the string
|
||||||
// representation of a signal like 'SIGKILL'. The nameOrID can be a container name
|
// representation of a signal like 'SIGKILL'. The nameOrID can be a container name
|
||||||
// or a partial/full ID
|
// or a partial/full ID
|
||||||
func Kill(ctx context.Context, nameOrID string, sig string, options *KillOptions) error {
|
func Kill(ctx context.Context, nameOrID string, options *KillOptions) error {
|
||||||
if options == nil {
|
if options == nil {
|
||||||
options = new(KillOptions)
|
options = new(KillOptions)
|
||||||
}
|
}
|
||||||
@ -142,7 +132,6 @@ func Kill(ctx context.Context, nameOrID string, sig string, options *KillOptions
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
params.Set("signal", sig)
|
|
||||||
response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/kill", params, nil, nameOrID)
|
response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/kill", params, nil, nameOrID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -180,9 +169,9 @@ func Restart(ctx context.Context, nameOrID string, options *RestartOptions) erro
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
params := url.Values{}
|
params, err := options.ToParams()
|
||||||
if options.Changed("Timeout") {
|
if err != nil {
|
||||||
params.Set("t", strconv.Itoa(options.GetTimeout()))
|
return err
|
||||||
}
|
}
|
||||||
response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/restart", params, nil, nameOrID)
|
response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/restart", params, nil, nameOrID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -335,9 +324,9 @@ func Wait(ctx context.Context, nameOrID string, options *WaitOptions) (int32, er
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return exitCode, err
|
return exitCode, err
|
||||||
}
|
}
|
||||||
params := url.Values{}
|
params, err := options.ToParams()
|
||||||
if options.Changed("Condition") {
|
if err != nil {
|
||||||
params.Set("condition", options.GetCondition().String())
|
return exitCode, err
|
||||||
}
|
}
|
||||||
response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/wait", params, nil, nameOrID)
|
response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/wait", params, nil, nameOrID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -123,7 +123,6 @@ type PruneOptions struct {
|
|||||||
//go:generate go run ../generator/generator.go RemoveOptions
|
//go:generate go run ../generator/generator.go RemoveOptions
|
||||||
// RemoveOptions are optional options for removing containers
|
// RemoveOptions are optional options for removing containers
|
||||||
type RemoveOptions struct {
|
type RemoveOptions struct {
|
||||||
All *bool
|
|
||||||
Ignore *bool
|
Ignore *bool
|
||||||
Force *bool
|
Force *bool
|
||||||
Volumes *bool
|
Volumes *bool
|
||||||
@ -138,6 +137,7 @@ type InspectOptions struct {
|
|||||||
//go:generate go run ../generator/generator.go KillOptions
|
//go:generate go run ../generator/generator.go KillOptions
|
||||||
// KillOptions are optional options for killing containers
|
// KillOptions are optional options for killing containers
|
||||||
type KillOptions struct {
|
type KillOptions struct {
|
||||||
|
Signal *string
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:generate go run ../generator/generator.go PauseOptions
|
//go:generate go run ../generator/generator.go PauseOptions
|
||||||
@ -177,11 +177,13 @@ type UnpauseOptions struct{}
|
|||||||
// WaitOptions are optional options for waiting on containers
|
// WaitOptions are optional options for waiting on containers
|
||||||
type WaitOptions struct {
|
type WaitOptions struct {
|
||||||
Condition *define.ContainerStatus
|
Condition *define.ContainerStatus
|
||||||
|
Interval *string
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:generate go run ../generator/generator.go StopOptions
|
//go:generate go run ../generator/generator.go StopOptions
|
||||||
// StopOptions are optional options for stopping containers
|
// StopOptions are optional options for stopping containers
|
||||||
type StopOptions struct {
|
type StopOptions struct {
|
||||||
|
Ignore *bool
|
||||||
Timeout *uint
|
Timeout *uint
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,3 +86,19 @@ func (o *KillOptions) ToParams() (url.Values, error) {
|
|||||||
}
|
}
|
||||||
return params, nil
|
return params, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithSignal
|
||||||
|
func (o *KillOptions) WithSignal(value string) *KillOptions {
|
||||||
|
v := &value
|
||||||
|
o.Signal = v
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSignal
|
||||||
|
func (o *KillOptions) GetSignal() string {
|
||||||
|
var signal string
|
||||||
|
if o.Signal == nil {
|
||||||
|
return signal
|
||||||
|
}
|
||||||
|
return *o.Signal
|
||||||
|
}
|
||||||
|
@ -87,22 +87,6 @@ func (o *RemoveOptions) ToParams() (url.Values, error) {
|
|||||||
return params, nil
|
return params, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithAll
|
|
||||||
func (o *RemoveOptions) WithAll(value bool) *RemoveOptions {
|
|
||||||
v := &value
|
|
||||||
o.All = v
|
|
||||||
return o
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAll
|
|
||||||
func (o *RemoveOptions) GetAll() bool {
|
|
||||||
var all bool
|
|
||||||
if o.All == nil {
|
|
||||||
return all
|
|
||||||
}
|
|
||||||
return *o.All
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithIgnore
|
// WithIgnore
|
||||||
func (o *RemoveOptions) WithIgnore(value bool) *RemoveOptions {
|
func (o *RemoveOptions) WithIgnore(value bool) *RemoveOptions {
|
||||||
v := &value
|
v := &value
|
||||||
|
@ -87,6 +87,22 @@ func (o *StopOptions) ToParams() (url.Values, error) {
|
|||||||
return params, nil
|
return params, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithIgnore
|
||||||
|
func (o *StopOptions) WithIgnore(value bool) *StopOptions {
|
||||||
|
v := &value
|
||||||
|
o.Ignore = v
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetIgnore
|
||||||
|
func (o *StopOptions) GetIgnore() bool {
|
||||||
|
var ignore bool
|
||||||
|
if o.Ignore == nil {
|
||||||
|
return ignore
|
||||||
|
}
|
||||||
|
return *o.Ignore
|
||||||
|
}
|
||||||
|
|
||||||
// WithTimeout
|
// WithTimeout
|
||||||
func (o *StopOptions) WithTimeout(value uint) *StopOptions {
|
func (o *StopOptions) WithTimeout(value uint) *StopOptions {
|
||||||
v := &value
|
v := &value
|
||||||
|
@ -103,3 +103,19 @@ func (o *WaitOptions) GetCondition() define.ContainerStatus {
|
|||||||
}
|
}
|
||||||
return *o.Condition
|
return *o.Condition
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithInterval
|
||||||
|
func (o *WaitOptions) WithInterval(value string) *WaitOptions {
|
||||||
|
v := &value
|
||||||
|
o.Interval = v
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInterval
|
||||||
|
func (o *WaitOptions) GetInterval() string {
|
||||||
|
var interval string
|
||||||
|
if o.Interval == nil {
|
||||||
|
return interval
|
||||||
|
}
|
||||||
|
return *o.Interval
|
||||||
|
}
|
||||||
|
@ -443,7 +443,7 @@ var _ = Describe("Podman containers ", func() {
|
|||||||
|
|
||||||
It("podman kill bogus container", func() {
|
It("podman kill bogus container", func() {
|
||||||
// Killing bogus container should return 404
|
// Killing bogus container should return 404
|
||||||
err := containers.Kill(bt.conn, "foobar", "SIGTERM", nil)
|
err := containers.Kill(bt.conn, "foobar", new(containers.KillOptions).WithSignal("SIGTERM"))
|
||||||
Expect(err).ToNot(BeNil())
|
Expect(err).ToNot(BeNil())
|
||||||
code, _ := bindings.CheckResponseCode(err)
|
code, _ := bindings.CheckResponseCode(err)
|
||||||
Expect(code).To(BeNumerically("==", http.StatusNotFound))
|
Expect(code).To(BeNumerically("==", http.StatusNotFound))
|
||||||
@ -454,7 +454,7 @@ var _ = Describe("Podman containers ", func() {
|
|||||||
var name = "top"
|
var name = "top"
|
||||||
_, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
|
_, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
err = containers.Kill(bt.conn, name, "SIGINT", nil)
|
err = containers.Kill(bt.conn, name, new(containers.KillOptions).WithSignal("SIGINT"))
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
_, err = containers.Exists(bt.conn, name, nil)
|
_, err = containers.Exists(bt.conn, name, nil)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
@ -465,7 +465,7 @@ var _ = Describe("Podman containers ", func() {
|
|||||||
var name = "top"
|
var name = "top"
|
||||||
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
|
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
err = containers.Kill(bt.conn, cid, "SIGTERM", nil)
|
err = containers.Kill(bt.conn, cid, new(containers.KillOptions).WithSignal("SIGTERM"))
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
_, err = containers.Exists(bt.conn, cid, nil)
|
_, err = containers.Exists(bt.conn, cid, nil)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
@ -476,7 +476,7 @@ var _ = Describe("Podman containers ", func() {
|
|||||||
var name = "top"
|
var name = "top"
|
||||||
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
|
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
err = containers.Kill(bt.conn, cid, "SIGKILL", nil)
|
err = containers.Kill(bt.conn, cid, new(containers.KillOptions).WithSignal("SIGKILL"))
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -485,7 +485,7 @@ var _ = Describe("Podman containers ", func() {
|
|||||||
var name = "top"
|
var name = "top"
|
||||||
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
|
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
err = containers.Kill(bt.conn, cid, "foobar", nil)
|
err = containers.Kill(bt.conn, cid, new(containers.KillOptions).WithSignal("foobar"))
|
||||||
Expect(err).ToNot(BeNil())
|
Expect(err).ToNot(BeNil())
|
||||||
code, _ := bindings.CheckResponseCode(err)
|
code, _ := bindings.CheckResponseCode(err)
|
||||||
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
|
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
|
||||||
@ -501,7 +501,7 @@ var _ = Describe("Podman containers ", func() {
|
|||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
containerLatestList, err := containers.List(bt.conn, new(containers.ListOptions).WithLast(1))
|
containerLatestList, err := containers.List(bt.conn, new(containers.ListOptions).WithLast(1))
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
err = containers.Kill(bt.conn, containerLatestList[0].Names[0], "SIGTERM", nil)
|
err = containers.Kill(bt.conn, containerLatestList[0].Names[0], new(containers.KillOptions).WithSignal("SIGTERM"))
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -81,11 +81,10 @@ type PauseUnpauseReport struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type StopOptions struct {
|
type StopOptions struct {
|
||||||
All bool
|
All bool
|
||||||
CIDFiles []string
|
Ignore bool
|
||||||
Ignore bool
|
Latest bool
|
||||||
Latest bool
|
Timeout *uint
|
||||||
Timeout *uint
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type StopReport struct {
|
type StopReport struct {
|
||||||
@ -104,10 +103,9 @@ type TopOptions struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type KillOptions struct {
|
type KillOptions struct {
|
||||||
All bool
|
All bool
|
||||||
Latest bool
|
Latest bool
|
||||||
Signal string
|
Signal string
|
||||||
CIDFiles []string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type KillReport struct {
|
type KillReport struct {
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -139,14 +138,6 @@ func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []st
|
|||||||
}
|
}
|
||||||
func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []string, options entities.StopOptions) ([]*entities.StopReport, error) {
|
func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []string, options entities.StopOptions) ([]*entities.StopReport, error) {
|
||||||
names := namesOrIds
|
names := namesOrIds
|
||||||
for _, cidFile := range options.CIDFiles {
|
|
||||||
content, err := ioutil.ReadFile(cidFile)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "error reading CIDFile")
|
|
||||||
}
|
|
||||||
id := strings.Split(string(content), "\n")[0]
|
|
||||||
names = append(names, id)
|
|
||||||
}
|
|
||||||
ctrs, err := getContainersByContext(options.All, options.Latest, names, ic.Libpod)
|
ctrs, err := getContainersByContext(options.All, options.Latest, names, ic.Libpod)
|
||||||
if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr) {
|
if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr) {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -202,14 +193,6 @@ func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities.
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []string, options entities.KillOptions) ([]*entities.KillReport, error) {
|
func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []string, options entities.KillOptions) ([]*entities.KillReport, error) {
|
||||||
for _, cidFile := range options.CIDFiles {
|
|
||||||
content, err := ioutil.ReadFile(cidFile)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "error reading CIDFile")
|
|
||||||
}
|
|
||||||
id := strings.Split(string(content), "\n")[0]
|
|
||||||
namesOrIds = append(namesOrIds, id)
|
|
||||||
}
|
|
||||||
sig, err := signal.ParseSignalNameOrNumber(options.Signal)
|
sig, err := signal.ParseSignalNameOrNumber(options.Signal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -41,7 +40,7 @@ func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []strin
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
responses := make([]entities.WaitReport, 0, len(cons))
|
responses := make([]entities.WaitReport, 0, len(cons))
|
||||||
options := new(containers.WaitOptions).WithCondition(opts.Condition)
|
options := new(containers.WaitOptions).WithCondition(opts.Condition).WithInterval(opts.Interval.String())
|
||||||
for _, c := range cons {
|
for _, c := range cons {
|
||||||
response := entities.WaitReport{Id: c.ID}
|
response := entities.WaitReport{Id: c.ID}
|
||||||
exitCode, err := containers.Wait(ic.ClientCtx, c.ID, options)
|
exitCode, err := containers.Wait(ic.ClientCtx, c.ID, options)
|
||||||
@ -83,19 +82,11 @@ func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []st
|
|||||||
|
|
||||||
func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []string, opts entities.StopOptions) ([]*entities.StopReport, error) {
|
func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []string, opts entities.StopOptions) ([]*entities.StopReport, error) {
|
||||||
reports := []*entities.StopReport{}
|
reports := []*entities.StopReport{}
|
||||||
for _, cidFile := range opts.CIDFiles {
|
|
||||||
content, err := ioutil.ReadFile(cidFile)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "error reading CIDFile")
|
|
||||||
}
|
|
||||||
id := strings.Split(string(content), "\n")[0]
|
|
||||||
namesOrIds = append(namesOrIds, id)
|
|
||||||
}
|
|
||||||
ctrs, err := getContainersByContext(ic.ClientCtx, opts.All, opts.Ignore, namesOrIds)
|
ctrs, err := getContainersByContext(ic.ClientCtx, opts.All, opts.Ignore, namesOrIds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
options := new(containers.StopOptions)
|
options := new(containers.StopOptions).WithIgnore(opts.Ignore)
|
||||||
if to := opts.Timeout; to != nil {
|
if to := opts.Timeout; to != nil {
|
||||||
options.WithTimeout(*to)
|
options.WithTimeout(*to)
|
||||||
}
|
}
|
||||||
@ -126,23 +117,16 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []string, opts entities.KillOptions) ([]*entities.KillReport, error) {
|
func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []string, opts entities.KillOptions) ([]*entities.KillReport, error) {
|
||||||
for _, cidFile := range opts.CIDFiles {
|
|
||||||
content, err := ioutil.ReadFile(cidFile)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "error reading CIDFile")
|
|
||||||
}
|
|
||||||
id := strings.Split(string(content), "\n")[0]
|
|
||||||
namesOrIds = append(namesOrIds, id)
|
|
||||||
}
|
|
||||||
ctrs, err := getContainersByContext(ic.ClientCtx, opts.All, false, namesOrIds)
|
ctrs, err := getContainersByContext(ic.ClientCtx, opts.All, false, namesOrIds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
options := new(containers.KillOptions).WithSignal(opts.Signal)
|
||||||
reports := make([]*entities.KillReport, 0, len(ctrs))
|
reports := make([]*entities.KillReport, 0, len(ctrs))
|
||||||
for _, c := range ctrs {
|
for _, c := range ctrs {
|
||||||
reports = append(reports, &entities.KillReport{
|
reports = append(reports, &entities.KillReport{
|
||||||
Id: c.ID,
|
Id: c.ID,
|
||||||
Err: containers.Kill(ic.ClientCtx, c.ID, opts.Signal, nil),
|
Err: containers.Kill(ic.ClientCtx, c.ID, options),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return reports, nil
|
return reports, nil
|
||||||
|
@ -167,4 +167,20 @@ var _ = Describe("Podman kill", func() {
|
|||||||
Expect(wait.ExitCode()).To(BeZero())
|
Expect(wait.ExitCode()).To(BeZero())
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("podman stop --all", func() {
|
||||||
|
session := podmanTest.RunTopContainer("")
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
|
||||||
|
|
||||||
|
session = podmanTest.RunTopContainer("")
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(2))
|
||||||
|
|
||||||
|
session = podmanTest.Podman([]string{"kill", "--all"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -225,4 +225,26 @@ var _ = Describe("Podman restart", func() {
|
|||||||
// line count should be equal
|
// line count should be equal
|
||||||
Expect(beforeRestart.OutputToString()).To(Equal(afterRestart.OutputToString()))
|
Expect(beforeRestart.OutputToString()).To(Equal(afterRestart.OutputToString()))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("podman restart --all", func() {
|
||||||
|
session := podmanTest.RunTopContainer("")
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
|
||||||
|
|
||||||
|
session = podmanTest.RunTopContainer("")
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(2))
|
||||||
|
|
||||||
|
session = podmanTest.Podman([]string{"stop", "--all"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
|
||||||
|
|
||||||
|
session = podmanTest.Podman([]string{"restart", "--all"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(2))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -164,13 +164,14 @@ var _ = Describe("Podman stop", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("podman stop container --timeout", func() {
|
It("podman stop container --timeout", func() {
|
||||||
session := podmanTest.RunTopContainer("test5")
|
session := podmanTest.Podman([]string{"run", "-d", "--name", "test5", ALPINE, "sleep", "100"})
|
||||||
session.WaitWithDefaultTimeout()
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(session.ExitCode()).To(Equal(0))
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
cid1 := session.OutputToString()
|
cid1 := session.OutputToString()
|
||||||
|
|
||||||
session = podmanTest.Podman([]string{"stop", "--timeout", "1", "test5"})
|
session = podmanTest.Podman([]string{"stop", "--timeout", "1", "test5"})
|
||||||
session.WaitWithDefaultTimeout()
|
// Without timeout container stops in 10 seconds
|
||||||
|
// If not stopped in 5 seconds, then --timeout did not work
|
||||||
|
session.Wait(5)
|
||||||
Expect(session.ExitCode()).To(Equal(0))
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
output := session.OutputToString()
|
output := session.OutputToString()
|
||||||
Expect(output).To(ContainSubstring(cid1))
|
Expect(output).To(ContainSubstring(cid1))
|
||||||
@ -307,4 +308,38 @@ var _ = Describe("Podman stop", func() {
|
|||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
Expect(result.ExitCode()).To(Equal(125))
|
Expect(result.ExitCode()).To(Equal(125))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("podman stop --all", func() {
|
||||||
|
session := podmanTest.RunTopContainer("")
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
|
||||||
|
|
||||||
|
session = podmanTest.RunTopContainer("")
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(2))
|
||||||
|
|
||||||
|
session = podmanTest.Podman([]string{"stop", "--all"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("podman stop --ignore", func() {
|
||||||
|
session := podmanTest.RunTopContainer("")
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
cid := session.OutputToString()
|
||||||
|
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
|
||||||
|
|
||||||
|
session = podmanTest.Podman([]string{"stop", "bogus", cid})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Equal(125))
|
||||||
|
|
||||||
|
session = podmanTest.Podman([]string{"stop", "--ignore", "bogus", cid})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
Reference in New Issue
Block a user