Files
podman/pkg/api/handlers/containers_attach.go
Brent Baude f1eaccedfa fix longname handling for bindings
the api needs to account for image input where the image is encoded as a fqd image name.

Signed-off-by: Brent Baude <bbaude@redhat.com>
2020-01-31 08:38:25 -06:00

160 lines
4.7 KiB
Go

package handlers
import (
"net/http"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/api/handlers/utils"
"github.com/gorilla/mux"
"github.com/gorilla/schema"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"k8s.io/client-go/tools/remotecommand"
)
func AttachContainer(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
DetachKeys string `schema:"detachKeys"`
Logs bool `schema:"logs"`
Stream bool `schema:"stream"`
Stdin bool `schema:"stdin"`
Stdout bool `schema:"stdout"`
Stderr bool `schema:"stderr"`
}{}
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
utils.Error(w, "Error parsing parameters", http.StatusBadRequest, err)
return
}
muxVars := mux.Vars(r)
// Detach keys: explicitly set to "" is very different from unset
// TODO: Our format for parsing these may be different from Docker.
var detachKeys *string
if _, found := muxVars["detachKeys"]; found {
detachKeys = &query.DetachKeys
}
streams := new(libpod.HTTPAttachStreams)
streams.Stdout = true
streams.Stderr = true
streams.Stdin = true
useStreams := false
if _, found := muxVars["stdin"]; found {
streams.Stdin = query.Stdin
useStreams = true
}
if _, found := muxVars["stdout"]; found {
streams.Stdout = query.Stdout
useStreams = true
}
if _, found := muxVars["stderr"]; found {
streams.Stderr = query.Stderr
useStreams = true
}
if !useStreams {
streams = nil
}
if useStreams && !streams.Stdout && !streams.Stderr && !streams.Stdin {
utils.Error(w, "Parameter conflict", http.StatusBadRequest, errors.Errorf("at least one of stdin, stdout, stderr must be true"))
return
}
// TODO: Investigate supporting these.
// Logs replays container logs over the attach socket.
// Stream seems to break things up somehow? Not 100% clear.
if query.Logs {
utils.Error(w, "Unsupported parameter", http.StatusBadRequest, errors.Errorf("the logs parameter to attach is not presently supported"))
return
}
// We only support stream=true or unset
if _, found := muxVars["stream"]; found && query.Stream {
utils.Error(w, "Unsupported parameter", http.StatusBadRequest, errors.Errorf("the stream parameter to attach is not presently supported"))
return
}
name := utils.GetName(r)
ctr, err := runtime.LookupContainer(name)
if err != nil {
utils.ContainerNotFound(w, name, err)
return
}
state, err := ctr.State()
if err != nil {
utils.InternalServerError(w, err)
return
}
if !(state == define.ContainerStateCreated || state == define.ContainerStateRunning) {
utils.InternalServerError(w, errors.Wrapf(define.ErrCtrStateInvalid, "can only attach to created or running containers"))
return
}
// Hijack the connection
hijacker, ok := w.(http.Hijacker)
if !ok {
utils.InternalServerError(w, errors.Errorf("unable to hijack connection"))
return
}
w.WriteHeader(http.StatusSwitchingProtocols)
connection, buffer, err := hijacker.Hijack()
if err != nil {
utils.InternalServerError(w, errors.Wrapf(err, "error hijacking connection"))
return
}
logrus.Debugf("Hijack for attach of container %s successful", ctr.ID())
// Perform HTTP attach.
// HTTPAttach will handle everything about the connection from here on
// (including closing it and writing errors to it).
if err := ctr.HTTPAttach(connection, buffer, streams, detachKeys, nil); err != nil {
// We can't really do anything about errors anymore. HTTPAttach
// should be writing them to the connection.
logrus.Errorf("Error attaching to container %s: %v", ctr.ID(), err)
}
logrus.Debugf("Attach for container %s completed successfully", ctr.ID())
}
func ResizeContainer(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
Height uint16 `schema:"h"`
Width uint16 `schema:"w"`
}{}
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
// This is not a 400, despite the fact that is should be, for
// compatibility reasons.
utils.InternalServerError(w, errors.Wrapf(err, "error parsing query options"))
return
}
name := utils.GetName(r)
ctr, err := runtime.LookupContainer(name)
if err != nil {
utils.ContainerNotFound(w, name, err)
return
}
newSize := remotecommand.TerminalSize{
Width: query.Width,
Height: query.Height,
}
if err := ctr.AttachResize(newSize); err != nil {
utils.InternalServerError(w, err)
return
}
// This is not a 204, even though we write nothing, for compatibility
// reasons.
utils.WriteResponse(w, http.StatusOK, "")
}