Skip to content

Commit

Permalink
Add bindings for exec and enable attached remote
Browse files Browse the repository at this point in the history
This adds bindings for starting exec sessions, and then uses them
to wire up detached exec. Code is heavily based on Attach code
for containers, slightly modified to handle exec sessions.

Bindings are presently attached-only, detached is pending on a
Conmon update landing in CI. I'll probably get to that next.

Signed-off-by: Matthew Heon <[email protected]>
  • Loading branch information
mheon committed Jun 1, 2020
1 parent 990514e commit 45a7e72
Show file tree
Hide file tree
Showing 8 changed files with 544 additions and 298 deletions.
4 changes: 2 additions & 2 deletions cmd/podman/containers/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,14 @@ func execFlags(flags *pflag.FlagSet) {

func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
Mode: []entities.EngineMode{entities.ABIMode},
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: execCommand,
})
flags := execCommand.Flags()
execFlags(flags)

registry.Commands = append(registry.Commands, registry.CliCommand{
Mode: []entities.EngineMode{entities.ABIMode},
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: containerExecCommand,
Parent: containerCmd,
})
Expand Down
4 changes: 3 additions & 1 deletion pkg/api/handlers/compat/resize.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"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"
"k8s.io/client-go/tools/remotecommand"
Expand Down Expand Up @@ -37,9 +38,9 @@ func ResizeTTY(w http.ResponseWriter, r *http.Request) {
}

var status int
name := utils.GetName(r)
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)
Expand All @@ -61,6 +62,7 @@ func ResizeTTY(w http.ResponseWriter, r *http.Request) {
// 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)
Expand Down
2 changes: 1 addition & 1 deletion pkg/api/server/register_exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ func (s *APIServer) registerExecHandlers(r *mux.Router) error {
// $ref: "#/responses/NoSuchExecInstance"
// 500:
// $ref: "#/responses/InternalError"
r.Handle(VersionedPath("/libpod/exec/{id}/resize"), s.APIHandler(compat.UnsupportedHandler)).Methods(http.MethodPost)
r.Handle(VersionedPath("/libpod/exec/{id}/resize"), s.APIHandler(compat.ResizeTTY)).Methods(http.MethodPost)
// swagger:operation GET /libpod/exec/{id}/json libpod libpodInspectExec
// ---
// tags:
Expand Down
60 changes: 21 additions & 39 deletions pkg/bindings/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (
)

var (
basePath = &url.URL{
BasePath = &url.URL{
Scheme: "http",
Host: "d",
Path: "/v" + APIVersion.String() + "/libpod",
Expand All @@ -37,15 +37,14 @@ type APIResponse struct {
}

type Connection struct {
_url *url.URL
client *http.Client
conn *net.Conn
Uri *url.URL
Client *http.Client
}

type valueKey string

const (
clientKey = valueKey("client")
clientKey = valueKey("Client")
)

// GetClient from context build by NewConnection()
Expand All @@ -59,7 +58,7 @@ func GetClient(ctx context.Context) (*Connection, error) {

// JoinURL elements with '/'
func JoinURL(elements ...string) string {
return strings.Join(elements, "/")
return "/" + strings.Join(elements, "/")
}

// NewConnection takes a URI as a string and returns a context with the
Expand Down Expand Up @@ -88,7 +87,7 @@ func NewConnection(ctx context.Context, uri string, identity ...string) (context
return nil, errors.Wrapf(err, "Value of PODMAN_HOST is not a valid url: %s", uri)
}

// Now we setup the http client to use the connection above
// Now we setup the http Client to use the connection above
var connection Connection
switch _url.Scheme {
case "ssh":
Expand Down Expand Up @@ -125,16 +124,12 @@ func NewConnection(ctx context.Context, uri string, identity ...string) (context

func tcpClient(_url *url.URL) (Connection, error) {
connection := Connection{
_url: _url,
Uri: _url,
}
connection.client = &http.Client{
connection.Client = &http.Client{
Transport: &http.Transport{
DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
conn, err := net.Dial("tcp", _url.Host)
if c, ok := ctx.Value(clientKey).(*Connection); ok {
c.conn = &conn
}
return conn, err
return net.Dial("tcp", _url.Host)
},
DisableCompression: true,
},
Expand Down Expand Up @@ -167,11 +162,11 @@ func pingNewConnection(ctx context.Context) error {
}

switch APIVersion.Compare(versionSrv) {
case 1, 0:
// Server's job when client version is equal or older
case -1, 0:
// Server's job when Client version is equal or older
return nil
case -1:
return errors.Errorf("server API version is too old. client %q server %q", APIVersion.String(), versionSrv.String())
case 1:
return errors.Errorf("server API version is too old. Client %q server %q", APIVersion.String(), versionSrv.String())
}
}
return errors.Errorf("ping response was %q", response.StatusCode)
Expand Down Expand Up @@ -217,31 +212,22 @@ func sshClient(_url *url.URL, identity string, secure bool) (Connection, error)
return Connection{}, errors.Wrapf(err, "Connection to bastion host (%s) failed.", _url.String())
}

connection := Connection{_url: _url}
connection.client = &http.Client{
connection := Connection{Uri: _url}
connection.Client = &http.Client{
Transport: &http.Transport{
DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
conn, err := bastion.Dial("unix", _url.Path)
if c, ok := ctx.Value(clientKey).(*Connection); ok {
c.conn = &conn
}
return conn, err
return bastion.Dial("unix", _url.Path)
},
}}
return connection, nil
}

func unixClient(_url *url.URL) (Connection, error) {
connection := Connection{_url: _url}
connection.client = &http.Client{
connection := Connection{Uri: _url}
connection.Client = &http.Client{
Transport: &http.Transport{
DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
d := net.Dialer{}
conn, err := d.DialContext(ctx, "unix", _url.Path)
if c, ok := ctx.Value(clientKey).(*Connection); ok {
c.conn = &conn
}
return conn, err
return (&net.Dialer{}).DialContext(ctx, "unix", _url.Path)
},
DisableCompression: true,
},
Expand All @@ -263,7 +249,7 @@ func (c *Connection) DoRequest(httpBody io.Reader, httpMethod, endpoint string,
// Lets eventually use URL for this which might lead to safer
// usage
safeEndpoint := fmt.Sprintf(endpoint, safePathValues...)
e := basePath.String() + safeEndpoint
e := BasePath.String() + safeEndpoint
req, err := http.NewRequest(httpMethod, e, httpBody)
if err != nil {
return nil, err
Expand All @@ -277,7 +263,7 @@ func (c *Connection) DoRequest(httpBody io.Reader, httpMethod, endpoint string,
req = req.WithContext(context.WithValue(context.Background(), clientKey, c))
// Give the Do three chances in the case of a comm/service hiccup
for i := 0; i < 3; i++ {
response, err = c.client.Do(req) // nolint
response, err = c.Client.Do(req) // nolint
if err == nil {
break
}
Expand All @@ -286,10 +272,6 @@ func (c *Connection) DoRequest(httpBody io.Reader, httpMethod, endpoint string,
return &APIResponse{response, req}, err
}

func (c *Connection) Write(b []byte) (int, error) {
return (*c.conn).Write(b)
}

// FiltersToString converts our typical filter format of a
// map[string][]string to a query/html safe string.
func FiltersToString(filters map[string][]string) (string, error) {
Expand Down
Loading

0 comments on commit 45a7e72

Please sign in to comment.