Files
Paul Holzinger 666f555aa5 Fix resize race with podman exec -it
When starting a process with `podman exec -it` the terminal is resized
after the process is started. To fix this allow exec start to accept the
terminal height and width as parameter and let it resize right before
the process is started.

Fixes #10560

Signed-off-by: Paul Holzinger <pholzing@redhat.com>
2021-06-16 16:43:30 +02:00

87 lines
2.5 KiB
Go

package compat
import (
"fmt"
"net/http"
"strings"
"github.com/containers/podman/v3/libpod"
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/api/handlers/utils"
"github.com/gorilla/mux"
"github.com/gorilla/schema"
"github.com/pkg/errors"
)
func ResizeTTY(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
// /containers/{id}/resize
query := struct {
Height uint16 `schema:"h"`
Width uint16 `schema:"w"`
IgnoreNotRunning bool `schema:"running"`
}{
// override any golang type defaults
}
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return
}
sz := define.TerminalSize{
Width: query.Width,
Height: query.Height,
}
var status int
switch {
case strings.Contains(r.URL.Path, "/containers/"):
name := utils.GetName(r)
ctnr, err := runtime.LookupContainer(name)
if err != nil {
utils.ContainerNotFound(w, name, err)
return
}
if err := ctnr.AttachResize(sz); err != nil {
if errors.Cause(err) != define.ErrCtrStateInvalid {
utils.InternalServerError(w, errors.Wrapf(err, "cannot resize container"))
} else {
utils.Error(w, "Container not running", http.StatusConflict, err)
}
return
}
// This is not a 204, even though we write nothing, for compatibility
// reasons.
status = http.StatusOK
case strings.Contains(r.URL.Path, "/exec/"):
name := mux.Vars(r)["id"]
ctnr, err := runtime.GetExecSessionContainer(name)
if err != nil {
utils.SessionNotFound(w, name, err)
return
}
if state, err := ctnr.State(); err != nil {
utils.InternalServerError(w, errors.Wrapf(err, "cannot obtain session container state"))
return
} else if state != define.ContainerStateRunning && !query.IgnoreNotRunning {
utils.Error(w, "Container not running", http.StatusConflict,
fmt.Errorf("container %q in wrong state %q", name, state.String()))
return
}
if err := ctnr.ExecResize(name, sz); err != nil {
if errors.Cause(err) != define.ErrExecSessionStateInvalid || !query.IgnoreNotRunning {
utils.InternalServerError(w, errors.Wrapf(err, "cannot resize session"))
return
}
}
// This is not a 204, even though we write nothing, for compatibility
// reasons.
status = http.StatusCreated
}
w.WriteHeader(status)
}