mirror of
https://github.com/containers/podman
synced 2024-10-19 16:54:07 +00: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:
parent
8f3bcf6247
commit
073f76c132
|
@ -2,8 +2,9 @@ package containers
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/common/pkg/completion"
|
||||
"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/pkg/domain/entities"
|
||||
"github.com/containers/podman/v2/pkg/signal"
|
||||
"github.com/pkg/errors"
|
||||
"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")
|
||||
_ = cmd.RegisterFlagCompletionFunc(signalFlagName, common.AutocompleteStopSignal)
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -94,6 +96,15 @@ func kill(_ *cobra.Command, args []string) error {
|
|||
if sig < 1 || sig > 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)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -3,6 +3,8 @@ package containers
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/common/pkg/completion"
|
||||
"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/validate"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||
"github.com/pkg/errors"
|
||||
"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")
|
||||
|
||||
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)
|
||||
|
||||
timeFlagName := "time"
|
||||
|
@ -97,6 +100,15 @@ func stop(cmd *cobra.Command, args []string) error {
|
|||
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)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -50,7 +50,7 @@ func waitFlags(cmd *cobra.Command) {
|
|||
flags := cmd.Flags()
|
||||
|
||||
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)
|
||||
|
||||
conditionFlagName := "condition"
|
||||
|
|
|
@ -31,11 +31,11 @@ import (
|
|||
func RemoveContainer(w http.ResponseWriter, r *http.Request) {
|
||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
||||
query := struct {
|
||||
All bool `schema:"all"`
|
||||
Force bool `schema:"force"`
|
||||
Ignore bool `schema:"ignore"`
|
||||
Link bool `schema:"link"`
|
||||
Volumes bool `schema:"v"`
|
||||
Force bool `schema:"force"`
|
||||
Ignore bool `schema:"ignore"`
|
||||
Link bool `schema:"link"`
|
||||
DockerVolumes bool `schema:"v"`
|
||||
LibpodVolumes bool `schema:"volumes"`
|
||||
}{
|
||||
// override any golang type defaults
|
||||
}
|
||||
|
@ -46,10 +46,19 @@ func RemoveContainer(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if query.Link && !utils.IsLibpodRequest(r) {
|
||||
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
|
||||
utils.ErrLinkNotSupport)
|
||||
return
|
||||
options := entities.RmOptions{
|
||||
Force: query.Force,
|
||||
Ignore: query.Ignore,
|
||||
}
|
||||
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)
|
||||
|
@ -57,12 +66,6 @@ func RemoveContainer(w http.ResponseWriter, r *http.Request) {
|
|||
// code.
|
||||
containerEngine := abi.ContainerEngine{Libpod: runtime}
|
||||
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)
|
||||
if err != nil {
|
||||
if errors.Cause(err) == define.ErrNoSuchCtr {
|
||||
|
@ -193,45 +196,48 @@ func KillContainer(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
sig, err := signal.ParseSignalNameOrNumber(query.Signal)
|
||||
if err != nil {
|
||||
utils.InternalServerError(w, err)
|
||||
return
|
||||
}
|
||||
// Now use the ABI implementation to prevent us from having duplicate
|
||||
// code.
|
||||
containerEngine := abi.ContainerEngine{Libpod: runtime}
|
||||
name := utils.GetName(r)
|
||||
con, err := runtime.LookupContainer(name)
|
||||
if err != nil {
|
||||
utils.ContainerNotFound(w, name, err)
|
||||
return
|
||||
options := entities.KillOptions{
|
||||
Signal: query.Signal,
|
||||
}
|
||||
|
||||
state, err := con.State()
|
||||
report, err := containerEngine.ContainerKill(r.Context(), []string{name}, options)
|
||||
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)
|
||||
return
|
||||
}
|
||||
|
||||
// If the Container is stopped already, send a 409
|
||||
if state == define.ContainerStateStopped || state == define.ContainerStateExited {
|
||||
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)))
|
||||
if len(report) > 0 && report[0].Err != nil {
|
||||
utils.InternalServerError(w, report[0].Err)
|
||||
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
|
||||
// SIGKILL.
|
||||
if !utils.IsLibpodRequest(r) && (signal == 0 || syscall.Signal(signal) == syscall.SIGKILL) {
|
||||
if _, err = con.Wait(); err != nil {
|
||||
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "failed to wait for Container %s", con.ID()))
|
||||
if !utils.IsLibpodRequest(r) {
|
||||
sig, err := signal.ParseSignalNameOrNumber(query.Signal)
|
||||
if err != nil {
|
||||
utils.InternalServerError(w, err)
|
||||
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
|
||||
utils.WriteResponse(w, http.StatusNoContent, nil)
|
||||
|
@ -242,6 +248,10 @@ func WaitContainer(w http.ResponseWriter, r *http.Request) {
|
|||
// /{version}/containers/(name)/wait
|
||||
exitCode, err := utils.WaitContainer(w, r)
|
||||
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)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -4,7 +4,10 @@ import (
|
|||
"net/http"
|
||||
|
||||
"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/domain/entities"
|
||||
"github.com/containers/podman/v2/pkg/domain/infra/abi"
|
||||
"github.com/gorilla/schema"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
@ -12,31 +15,46 @@ import (
|
|||
func RestartContainer(w http.ResponseWriter, r *http.Request) {
|
||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
||||
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
|
||||
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 {
|
||||
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
|
||||
}
|
||||
|
||||
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 {
|
||||
utils.ContainerNotFound(w, name, err)
|
||||
if errors.Cause(err) == define.ErrNoSuchCtr {
|
||||
utils.ContainerNotFound(w, name, err)
|
||||
return
|
||||
}
|
||||
|
||||
utils.InternalServerError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
timeout := con.StopTimeout()
|
||||
if _, found := r.URL.Query()["t"]; found {
|
||||
timeout = uint(query.Timeout)
|
||||
}
|
||||
|
||||
if err := con.RestartWithTimeout(r.Context(), timeout); err != nil {
|
||||
utils.InternalServerError(w, err)
|
||||
if len(report) > 0 && report[0].Err != nil {
|
||||
utils.InternalServerError(w, report[0].Err)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@ import (
|
|||
"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/domain/entities"
|
||||
"github.com/containers/podman/v2/pkg/domain/infra/abi"
|
||||
"github.com/gorilla/schema"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
@ -13,10 +15,15 @@ import (
|
|||
func StopContainer(w http.ResponseWriter, r *http.Request) {
|
||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
||||
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
|
||||
query := struct {
|
||||
Timeout int `schema:"t"`
|
||||
Ignore bool `schema:"ignore"`
|
||||
DockerTimeout uint `schema:"t"`
|
||||
LibpodTimeout uint `schema:"timeout"`
|
||||
}{
|
||||
// override any golang type defaults
|
||||
}
|
||||
|
@ -27,31 +34,46 @@ func StopContainer(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
utils.ContainerNotFound(w, name, err)
|
||||
return
|
||||
}
|
||||
|
||||
state, err := con.State()
|
||||
if err != nil {
|
||||
utils.InternalServerError(w, errors.Wrapf(err, "unable to get state for Container %s", name))
|
||||
utils.InternalServerError(w, err)
|
||||
return
|
||||
}
|
||||
// If the Container is stopped already, send a 304
|
||||
if state == define.ContainerStateStopped || state == define.ContainerStateExited {
|
||||
utils.WriteResponse(w, http.StatusNotModified, nil)
|
||||
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
|
||||
if query.Timeout > 0 {
|
||||
stopError = con.StopWithTimeout(uint(query.Timeout))
|
||||
} else {
|
||||
stopError = con.Stop()
|
||||
utils.InternalServerError(w, err)
|
||||
return
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -148,6 +148,12 @@ func GetContainer(w http.ResponseWriter, r *http.Request) {
|
|||
func WaitContainer(w http.ResponseWriter, r *http.Request) {
|
||||
exitCode, err := utils.WaitContainer(w, r)
|
||||
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
|
||||
}
|
||||
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/define"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||
"github.com/containers/podman/v2/pkg/domain/infra/abi"
|
||||
"github.com/gorilla/schema"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
@ -16,10 +18,13 @@ func WaitContainer(w http.ResponseWriter, r *http.Request) (int32, error) {
|
|||
interval time.Duration
|
||||
)
|
||||
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)
|
||||
query := struct {
|
||||
Interval string `schema:"interval"`
|
||||
Condition string `schema:"condition"`
|
||||
Interval string `schema:"interval"`
|
||||
Condition define.ContainerStatus `schema:"condition"`
|
||||
}{
|
||||
// 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()))
|
||||
return 0, err
|
||||
}
|
||||
options := entities.WaitOptions{
|
||||
Condition: define.ContainerStateStopped,
|
||||
}
|
||||
name := GetName(r)
|
||||
if _, found := r.URL.Query()["interval"]; found {
|
||||
interval, err = time.ParseDuration(query.Interval)
|
||||
if err != nil {
|
||||
|
@ -40,19 +49,19 @@ func WaitContainer(w http.ResponseWriter, r *http.Request) (int32, error) {
|
|||
return 0, err
|
||||
}
|
||||
}
|
||||
condition := define.ContainerStateStopped
|
||||
options.Interval = interval
|
||||
|
||||
if _, found := r.URL.Query()["condition"]; found {
|
||||
condition, err = define.StringToContainerStatus(query.Condition)
|
||||
if err != nil {
|
||||
InternalServerError(w, err)
|
||||
return 0, err
|
||||
}
|
||||
options.Condition = query.Condition
|
||||
}
|
||||
name := GetName(r)
|
||||
con, err := runtime.LookupContainer(name)
|
||||
|
||||
report, err := containerEngine.ContainerWait(r.Context(), []string{name}, options)
|
||||
if err != nil {
|
||||
ContainerNotFound(w, name, 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
|
||||
// description: the name or ID of the container
|
||||
// - in: query
|
||||
// name: all
|
||||
// type: boolean
|
||||
// default: false
|
||||
// description: Send kill signal to all containers
|
||||
// - in: query
|
||||
// name: signal
|
||||
// type: string
|
||||
// default: TERM
|
||||
|
@ -486,6 +491,11 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error {
|
|||
// - paused
|
||||
// - running
|
||||
// - stopped
|
||||
// - in: query
|
||||
// name: interval
|
||||
// type: string
|
||||
// default: "250ms"
|
||||
// description: Time Interval to wait before polling for completion.
|
||||
// produces:
|
||||
// - application/json
|
||||
// responses:
|
||||
|
@ -1219,9 +1229,20 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error {
|
|||
// required: true
|
||||
// description: the name or ID of the container
|
||||
// - in: query
|
||||
// name: t
|
||||
// name: all
|
||||
// type: boolean
|
||||
// default: false
|
||||
// description: Stop all containers
|
||||
// - in: query
|
||||
// name: timeout
|
||||
// type: integer
|
||||
// default: 10
|
||||
// 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:
|
||||
// - application/json
|
||||
// responses:
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/podman/v2/libpod/define"
|
||||
|
@ -83,18 +82,9 @@ func Remove(ctx context.Context, nameOrID string, options *RemoveOptions) error
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params := url.Values{}
|
||||
if v := options.GetVolumes(); options.Changed("Volumes") {
|
||||
params.Set("v", strconv.FormatBool(v))
|
||||
}
|
||||
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))
|
||||
params, err := options.ToParams()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
response, err := conn.DoRequest(nil, http.MethodDelete, "/containers/%s", params, nil, nameOrID)
|
||||
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
|
||||
// representation of a signal like 'SIGKILL'. The nameOrID can be a container name
|
||||
// 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 {
|
||||
options = new(KillOptions)
|
||||
}
|
||||
|
@ -142,7 +132,6 @@ func Kill(ctx context.Context, nameOrID string, sig string, options *KillOptions
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params.Set("signal", sig)
|
||||
response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/kill", params, nil, nameOrID)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -180,9 +169,9 @@ func Restart(ctx context.Context, nameOrID string, options *RestartOptions) erro
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params := url.Values{}
|
||||
if options.Changed("Timeout") {
|
||||
params.Set("t", strconv.Itoa(options.GetTimeout()))
|
||||
params, err := options.ToParams()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/restart", params, nil, nameOrID)
|
||||
if err != nil {
|
||||
|
@ -335,9 +324,9 @@ func Wait(ctx context.Context, nameOrID string, options *WaitOptions) (int32, er
|
|||
if err != nil {
|
||||
return exitCode, err
|
||||
}
|
||||
params := url.Values{}
|
||||
if options.Changed("Condition") {
|
||||
params.Set("condition", options.GetCondition().String())
|
||||
params, err := options.ToParams()
|
||||
if err != nil {
|
||||
return exitCode, err
|
||||
}
|
||||
response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/wait", params, nil, nameOrID)
|
||||
if err != nil {
|
||||
|
|
|
@ -123,7 +123,6 @@ type PruneOptions struct {
|
|||
//go:generate go run ../generator/generator.go RemoveOptions
|
||||
// RemoveOptions are optional options for removing containers
|
||||
type RemoveOptions struct {
|
||||
All *bool
|
||||
Ignore *bool
|
||||
Force *bool
|
||||
Volumes *bool
|
||||
|
@ -138,6 +137,7 @@ type InspectOptions struct {
|
|||
//go:generate go run ../generator/generator.go KillOptions
|
||||
// KillOptions are optional options for killing containers
|
||||
type KillOptions struct {
|
||||
Signal *string
|
||||
}
|
||||
|
||||
//go:generate go run ../generator/generator.go PauseOptions
|
||||
|
@ -177,11 +177,13 @@ type UnpauseOptions struct{}
|
|||
// WaitOptions are optional options for waiting on containers
|
||||
type WaitOptions struct {
|
||||
Condition *define.ContainerStatus
|
||||
Interval *string
|
||||
}
|
||||
|
||||
//go:generate go run ../generator/generator.go StopOptions
|
||||
// StopOptions are optional options for stopping containers
|
||||
type StopOptions struct {
|
||||
Ignore *bool
|
||||
Timeout *uint
|
||||
}
|
||||
|
||||
|
|
|
@ -86,3 +86,19 @@ func (o *KillOptions) ToParams() (url.Values, error) {
|
|||
}
|
||||
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
|
||||
}
|
||||
|
||||
// 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
|
||||
func (o *RemoveOptions) WithIgnore(value bool) *RemoveOptions {
|
||||
v := &value
|
||||
|
|
|
@ -87,6 +87,22 @@ func (o *StopOptions) ToParams() (url.Values, error) {
|
|||
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
|
||||
func (o *StopOptions) WithTimeout(value uint) *StopOptions {
|
||||
v := &value
|
||||
|
|
|
@ -103,3 +103,19 @@ func (o *WaitOptions) GetCondition() define.ContainerStatus {
|
|||
}
|
||||
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() {
|
||||
// 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())
|
||||
code, _ := bindings.CheckResponseCode(err)
|
||||
Expect(code).To(BeNumerically("==", http.StatusNotFound))
|
||||
|
@ -454,7 +454,7 @@ var _ = Describe("Podman containers ", func() {
|
|||
var name = "top"
|
||||
_, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
|
||||
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())
|
||||
_, err = containers.Exists(bt.conn, name, nil)
|
||||
Expect(err).To(BeNil())
|
||||
|
@ -465,7 +465,7 @@ var _ = Describe("Podman containers ", func() {
|
|||
var name = "top"
|
||||
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
|
||||
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())
|
||||
_, err = containers.Exists(bt.conn, cid, nil)
|
||||
Expect(err).To(BeNil())
|
||||
|
@ -476,7 +476,7 @@ var _ = Describe("Podman containers ", func() {
|
|||
var name = "top"
|
||||
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
|
||||
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())
|
||||
})
|
||||
|
||||
|
@ -485,7 +485,7 @@ var _ = Describe("Podman containers ", func() {
|
|||
var name = "top"
|
||||
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
|
||||
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())
|
||||
code, _ := bindings.CheckResponseCode(err)
|
||||
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
|
||||
|
@ -501,7 +501,7 @@ var _ = Describe("Podman containers ", func() {
|
|||
Expect(err).To(BeNil())
|
||||
containerLatestList, err := containers.List(bt.conn, new(containers.ListOptions).WithLast(1))
|
||||
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())
|
||||
})
|
||||
|
||||
|
|
|
@ -81,11 +81,10 @@ type PauseUnpauseReport struct {
|
|||
}
|
||||
|
||||
type StopOptions struct {
|
||||
All bool
|
||||
CIDFiles []string
|
||||
Ignore bool
|
||||
Latest bool
|
||||
Timeout *uint
|
||||
All bool
|
||||
Ignore bool
|
||||
Latest bool
|
||||
Timeout *uint
|
||||
}
|
||||
|
||||
type StopReport struct {
|
||||
|
@ -104,10 +103,9 @@ type TopOptions struct {
|
|||
}
|
||||
|
||||
type KillOptions struct {
|
||||
All bool
|
||||
Latest bool
|
||||
Signal string
|
||||
CIDFiles []string
|
||||
All bool
|
||||
Latest bool
|
||||
Signal string
|
||||
}
|
||||
|
||||
type KillReport struct {
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"io/ioutil"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"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) {
|
||||
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)
|
||||
if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr) {
|
||||
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) {
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -41,7 +40,7 @@ func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []strin
|
|||
return nil, err
|
||||
}
|
||||
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 {
|
||||
response := entities.WaitReport{Id: c.ID}
|
||||
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) {
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
options := new(containers.StopOptions)
|
||||
options := new(containers.StopOptions).WithIgnore(opts.Ignore)
|
||||
if to := opts.Timeout; to != nil {
|
||||
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) {
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
options := new(containers.KillOptions).WithSignal(opts.Signal)
|
||||
reports := make([]*entities.KillReport, 0, len(ctrs))
|
||||
for _, c := range ctrs {
|
||||
reports = append(reports, &entities.KillReport{
|
||||
Id: c.ID,
|
||||
Err: containers.Kill(ic.ClientCtx, c.ID, opts.Signal, nil),
|
||||
Err: containers.Kill(ic.ClientCtx, c.ID, options),
|
||||
})
|
||||
}
|
||||
return reports, nil
|
||||
|
|
|
@ -167,4 +167,20 @@ var _ = Describe("Podman kill", func() {
|
|||
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
|
||||
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() {
|
||||
session := podmanTest.RunTopContainer("test5")
|
||||
session := podmanTest.Podman([]string{"run", "-d", "--name", "test5", ALPINE, "sleep", "100"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
cid1 := session.OutputToString()
|
||||
|
||||
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))
|
||||
output := session.OutputToString()
|
||||
Expect(output).To(ContainSubstring(cid1))
|
||||
|
@ -307,4 +308,38 @@ var _ = Describe("Podman stop", func() {
|
|||
result.WaitWithDefaultTimeout()
|
||||
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))
|
||||
})
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue