Merge pull request #9051 from rhatdan/rm

Switch podman stop/kill/wait handlers to use abi
This commit is contained in:
OpenShift Merge Robot
2021-02-01 08:47:54 -05:00
committed by GitHub
22 changed files with 344 additions and 174 deletions

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)))

View File

@ -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
}

View File

@ -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: