mirror of
https://github.com/containers/podman.git
synced 2025-06-22 01:48:54 +08:00
Wire in endpoint for ExecStart
This is still very early not not well tested, and missing resize capability, but it does provide the first bits of exec. Signed-off-by: Matthew Heon <mheon@redhat.com>
This commit is contained in:

committed by
Matthew Heon

parent
50cc56bc4a
commit
ce56b68871
@ -13,6 +13,12 @@ import (
|
|||||||
"k8s.io/client-go/tools/remotecommand"
|
"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) {
|
func AttachContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
||||||
@ -106,10 +112,7 @@ func AttachContainer(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// This header string sourced from Docker:
|
fmt.Fprintf(connection, AttachHeader)
|
||||||
// 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")
|
|
||||||
|
|
||||||
logrus.Debugf("Hijack for attach of container %s successful", ctr.ID())
|
logrus.Debugf("Hijack for attach of container %s successful", ctr.ID())
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/containers/libpod/pkg/api/handlers"
|
"github.com/containers/libpod/pkg/api/handlers"
|
||||||
"github.com/containers/libpod/pkg/api/handlers/utils"
|
"github.com/containers/libpod/pkg/api/handlers/utils"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/gorilla/schema"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
@ -105,3 +106,76 @@ func ExecInspectHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
utils.WriteResponse(w, http.StatusOK, inspectOut)
|
utils.WriteResponse(w, http.StatusOK, inspectOut)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExecStartHandler runs a given exec session.
|
||||||
|
func ExecStartHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
||||||
|
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
||||||
|
|
||||||
|
sessionID := mux.Vars(r)["id"]
|
||||||
|
|
||||||
|
// TODO: Need to support these
|
||||||
|
query := struct {
|
||||||
|
Detach bool `schema:"Detach"`
|
||||||
|
Tty bool `schema:"Tty"`
|
||||||
|
}{
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, found := r.URL.Query()["Detach"]; found {
|
||||||
|
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
|
||||||
|
errors.Errorf("Detached exec is not yet supported"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, found := r.URL.Query()["Tty"]; found {
|
||||||
|
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
|
||||||
|
errors.Errorf("overriding terminal setting in ExecStart is not yet supported"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
@ -97,10 +97,10 @@ func (s *APIServer) registerExecHandlers(r *mux.Router) error {
|
|||||||
// properties:
|
// properties:
|
||||||
// Detach:
|
// Detach:
|
||||||
// type: boolean
|
// type: boolean
|
||||||
// description: Detach from the command
|
// description: Detach from the command. Not presently supported.
|
||||||
// Tty:
|
// Tty:
|
||||||
// type: boolean
|
// type: boolean
|
||||||
// description: Allocate a pseudo-TTY
|
// description: Allocate a pseudo-TTY. Not presently supported.
|
||||||
// produces:
|
// produces:
|
||||||
// - application/json
|
// - application/json
|
||||||
// responses:
|
// responses:
|
||||||
@ -109,10 +109,10 @@ func (s *APIServer) registerExecHandlers(r *mux.Router) error {
|
|||||||
// 404:
|
// 404:
|
||||||
// $ref: "#/responses/NoSuchExecInstance"
|
// $ref: "#/responses/NoSuchExecInstance"
|
||||||
// 409:
|
// 409:
|
||||||
// description: container is stopped or paused
|
// description: container is not running
|
||||||
// 500:
|
// 500:
|
||||||
// $ref: "#/responses/InternalError"
|
// $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
|
// 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.UnsupportedHandler)).Methods(http.MethodPost)
|
||||||
// swagger:operation POST /exec/{id}/resize compat resizeExec
|
// swagger:operation POST /exec/{id}/resize compat resizeExec
|
||||||
|
Reference in New Issue
Block a user