mirror of
https://github.com/containers/podman.git
synced 2025-08-16 20:53:13 +08:00

The biggest obstacle here was cleanup - we needed a way to remove detached exec sessions after they exited, but there's no way to tell if an exec session will be attached or detached when it's created, and that's when we must add the exit command that would do the removal. The solution was adding a delay to the exit command (5 minutes), which gives sufficient time for attached exec sessions to retrieve the exit code of the session after it exits, but still guarantees that they will be removed, even for detached sessions. This requires Conmon 2.0.17, which has the new `--exit-delay` flag. As part of the exit command rework, we can drop the hack we were using to clean up exec sessions (remove them as part of inspect). This is a lot cleaner, and I'm a lot happier about it. Otherwise, this is just plumbing - we need a bindings call for detached exec, and that needed to be added to the tunnel mode backend for entities. Signed-off-by: Matthew Heon <matthew.heon@pm.me>
101 lines
2.5 KiB
Go
101 lines
2.5 KiB
Go
package containers
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/containers/libpod/libpod/define"
|
|
"github.com/containers/libpod/pkg/api/handlers"
|
|
"github.com/containers/libpod/pkg/bindings"
|
|
jsoniter "github.com/json-iterator/go"
|
|
"github.com/pkg/errors"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
|
|
|
// ExecCreate creates a new exec session in an existing container.
|
|
// The exec session will not be started; that is done with ExecStart.
|
|
// Returns ID of new exec session, or an error if one occurred.
|
|
func ExecCreate(ctx context.Context, nameOrID string, config *handlers.ExecCreateConfig) (string, error) {
|
|
conn, err := bindings.GetClient(ctx)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if config == nil {
|
|
return "", errors.Errorf("must provide a configuration for exec session")
|
|
}
|
|
|
|
requestJSON, err := json.Marshal(config)
|
|
if err != nil {
|
|
return "", errors.Wrapf(err, "error marshalling exec config to JSON")
|
|
}
|
|
jsonReader := strings.NewReader(string(requestJSON))
|
|
|
|
resp, err := conn.DoRequest(jsonReader, http.MethodPost, "/containers/%s/exec", nil, nil, nameOrID)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
respStruct := new(handlers.ExecCreateResponse)
|
|
if err := resp.Process(respStruct); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return respStruct.ID, nil
|
|
}
|
|
|
|
// ExecInspect inspects an existing exec session, returning detailed information
|
|
// about it.
|
|
func ExecInspect(ctx context.Context, sessionID string) (*define.InspectExecSession, error) {
|
|
conn, err := bindings.GetClient(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
logrus.Debugf("Inspecting session ID %q", sessionID)
|
|
|
|
resp, err := conn.DoRequest(nil, http.MethodGet, "/exec/%s/json", nil, nil, sessionID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
respStruct := new(define.InspectExecSession)
|
|
if err := resp.Process(respStruct); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return respStruct, nil
|
|
}
|
|
|
|
// ExecStart starts (but does not attach to) a given exec session.
|
|
func ExecStart(ctx context.Context, sessionID string) error {
|
|
conn, err := bindings.GetClient(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
logrus.Debugf("Starting exec session ID %q", sessionID)
|
|
|
|
// We force Detach to true
|
|
body := struct {
|
|
Detach bool `json:"Detach"`
|
|
}{
|
|
Detach: true,
|
|
}
|
|
bodyJSON, err := json.Marshal(body)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
resp, err := conn.DoRequest(bytes.NewReader(bodyJSON), http.MethodPost, "/exec/%s/start", nil, nil, sessionID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return resp.Process(nil)
|
|
}
|