Merge pull request #5831 from mheon/exec_http_attach

APIv2 ExecStart (Attached Only)
This commit is contained in:
OpenShift Merge Robot
2020-05-15 13:19:43 -07:00
committed by GitHub
9 changed files with 680 additions and 221 deletions

View File

@ -13,6 +13,12 @@ import (
"k8s.io/client-go/tools/remotecommand"
)
// AttachHeader is the literal header sent for upgraded/hijacked connections for
// attach, sourced from Docker at:
// https://raw.githubusercontent.com/moby/moby/b95fad8e51bd064be4f4e58a996924f343846c85/api/server/router/container/container_routes.go
// Using literally to ensure compatibility with existing clients.
const AttachHeader = "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\r\n"
func AttachContainer(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
@ -106,10 +112,7 @@ func AttachContainer(w http.ResponseWriter, r *http.Request) {
return
}
// This header string sourced from Docker:
// https://raw.githubusercontent.com/moby/moby/b95fad8e51bd064be4f4e58a996924f343846c85/api/server/router/container/container_routes.go
// Using literally to ensure compatibility with existing clients.
fmt.Fprintf(connection, "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\r\n")
fmt.Fprintf(connection, AttachHeader)
logrus.Debugf("Hijack for attach of container %s successful", ctr.ID())

View File

@ -104,4 +104,76 @@ func ExecInspectHandler(w http.ResponseWriter, r *http.Request) {
}
utils.WriteResponse(w, http.StatusOK, inspectOut)
// Only for the Compat API: we want to remove sessions that were
// stopped. This is very hacky, but should suffice for now.
if !utils.IsLibpodRequest(r) && inspectOut.CanRemove {
logrus.Infof("Pruning stale exec session %s from container %s", sessionID, sessionCtr.ID())
if err := sessionCtr.ExecRemove(sessionID, false); err != nil && errors.Cause(err) != define.ErrNoSuchExecSession {
logrus.Errorf("Error removing stale exec session %s from container %s: %v", sessionID, sessionCtr.ID(), err)
}
}
}
// ExecStartHandler runs a given exec session.
func ExecStartHandler(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
sessionID := mux.Vars(r)["id"]
// TODO: We should read/support Tty and Detach from here.
bodyParams := new(handlers.ExecStartConfig)
if err := json.NewDecoder(r.Body).Decode(&bodyParams); err != nil {
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
errors.Wrapf(err, "failed to decode parameters for %s", r.URL.String()))
return
}
if bodyParams.Detach {
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
errors.Errorf("Detached exec is not yet supported"))
return
}
// TODO: Verify TTY setting against what inspect session was made with
sessionCtr, err := runtime.GetExecSessionContainer(sessionID)
if err != nil {
utils.Error(w, fmt.Sprintf("No such exec session: %s", sessionID), http.StatusNotFound, err)
return
}
logrus.Debugf("Starting exec session %s of container %s", sessionID, sessionCtr.ID())
state, err := sessionCtr.State()
if err != nil {
utils.InternalServerError(w, err)
return
}
if state != define.ContainerStateRunning {
utils.Error(w, http.StatusText(http.StatusConflict), http.StatusConflict, errors.Errorf("cannot exec in a container that is not running; container %s is %s", sessionCtr.ID(), state.String()))
return
}
// Hijack the connection
hijacker, ok := w.(http.Hijacker)
if !ok {
utils.InternalServerError(w, errors.Errorf("unable to hijack connection"))
return
}
connection, buffer, err := hijacker.Hijack()
if err != nil {
utils.InternalServerError(w, errors.Wrapf(err, "error hijacking connection"))
return
}
fmt.Fprintf(connection, AttachHeader)
logrus.Debugf("Hijack for attach of container %s exec session %s successful", sessionCtr.ID(), sessionID)
if err := sessionCtr.ExecHTTPStartAndAttach(sessionID, connection, buffer, nil, nil, nil); err != nil {
logrus.Errorf("Error attaching to container %s exec session %s: %v", sessionCtr.ID(), sessionID, err)
}
logrus.Debugf("Attach for container %s exec session %s completed successfully", sessionCtr.ID(), sessionID)
}

View File

@ -170,6 +170,11 @@ type ExecCreateResponse struct {
docker.IDResponse
}
type ExecStartConfig struct {
Detach bool `json:"Detach"`
Tty bool `json:"Tty"`
}
func ImageToImageSummary(l *libpodImage.Image) (*entities.ImageSummary, error) {
containers, err := l.Containers()
if err != nil {

View File

@ -97,10 +97,10 @@ func (s *APIServer) registerExecHandlers(r *mux.Router) error {
// properties:
// Detach:
// type: boolean
// description: Detach from the command
// description: Detach from the command. Not presently supported.
// Tty:
// type: boolean
// description: Allocate a pseudo-TTY
// description: Allocate a pseudo-TTY. Presently ignored.
// produces:
// - application/json
// responses:
@ -109,12 +109,12 @@ func (s *APIServer) registerExecHandlers(r *mux.Router) error {
// 404:
// $ref: "#/responses/NoSuchExecInstance"
// 409:
// description: container is stopped or paused
// description: container is not running
// 500:
// $ref: "#/responses/InternalError"
r.Handle(VersionedPath("/exec/{id}/start"), s.APIHandler(compat.UnsupportedHandler)).Methods(http.MethodPost)
r.Handle(VersionedPath("/exec/{id}/start"), s.APIHandler(compat.ExecStartHandler)).Methods(http.MethodPost)
// Added non version path to URI to support docker non versioned paths
r.Handle("/exec/{id}/start", s.APIHandler(compat.UnsupportedHandler)).Methods(http.MethodPost)
r.Handle("/exec/{id}/start", s.APIHandler(compat.ExecStartHandler)).Methods(http.MethodPost)
// swagger:operation POST /exec/{id}/resize compat resizeExec
// ---
// tags:
@ -153,7 +153,7 @@ func (s *APIServer) registerExecHandlers(r *mux.Router) error {
// tags:
// - exec (compat)
// summary: Inspect an exec instance
// description: Return low-level information about an exec instance.
// description: Return low-level information about an exec instance. Stale (stopped) exec sessions will be auto-removed after inspect runs.
// parameters:
// - in: path
// name: id
@ -264,10 +264,10 @@ func (s *APIServer) registerExecHandlers(r *mux.Router) error {
// properties:
// Detach:
// type: boolean
// description: Detach from the command
// description: Detach from the command. Not presently supported.
// Tty:
// type: boolean
// description: Allocate a pseudo-TTY
// description: Allocate a pseudo-TTY. Presently ignored.
// produces:
// - application/json
// responses:
@ -276,10 +276,10 @@ func (s *APIServer) registerExecHandlers(r *mux.Router) error {
// 404:
// $ref: "#/responses/NoSuchExecInstance"
// 409:
// description: container is stopped or paused
// description: container is not running.
// 500:
// $ref: "#/responses/InternalError"
r.Handle(VersionedPath("/libpod/exec/{id}/start"), s.APIHandler(compat.UnsupportedHandler)).Methods(http.MethodPost)
r.Handle(VersionedPath("/libpod/exec/{id}/start"), s.APIHandler(compat.ExecStartHandler)).Methods(http.MethodPost)
// swagger:operation POST /libpod/exec/{id}/resize libpod libpodResizeExec
// ---
// tags: