mirror of
https://github.com/containers/podman.git
synced 2025-10-29 00:38:34 +08:00
Merge pull request #9051 from rhatdan/rm
Switch podman stop/kill/wait handlers to use abi
This commit is contained in:
@ -32,11 +32,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
|
||||
}
|
||||
@ -47,10 +47,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)
|
||||
@ -58,12 +67,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 {
|
||||
@ -194,45 +197,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)
|
||||
@ -243,6 +249,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:
|
||||
|
||||
Reference in New Issue
Block a user