summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libpod/container_exec.go49
-rw-r--r--libpod/oci.go12
-rw-r--r--libpod/oci_conmon_exec_linux.go43
-rw-r--r--libpod/oci_missing.go5
4 files changed, 101 insertions, 8 deletions
diff --git a/libpod/container_exec.go b/libpod/container_exec.go
index 088bd0fd5..a38f22488 100644
--- a/libpod/container_exec.go
+++ b/libpod/container_exec.go
@@ -214,11 +214,52 @@ func (c *Container) ExecCreate(config *ExecConfig) (string, error) {
}
// ExecStart starts an exec session in the container, but does not attach to it.
-// Returns immediately upon starting the exec session.
+// Returns immediately upon starting the exec session, unlike other ExecStart
+// functions, which will only return when the exec session exits.
func (c *Container) ExecStart(sessionID string) error {
- // Will be implemented in part 2, migrating Start and implementing
- // detached Start.
- return define.ErrNotImplemented
+ if !c.batched {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+
+ if err := c.syncContainer(); err != nil {
+ return err
+ }
+ }
+
+ // Verify that we are in a good state to continue
+ if !c.ensureState(define.ContainerStateRunning) {
+ return errors.Wrapf(define.ErrCtrStateInvalid, "can only start exec sessions when their container is running")
+ }
+
+ session, ok := c.state.ExecSessions[sessionID]
+ if !ok {
+ return errors.Wrapf(define.ErrNoSuchExecSession, "container %s has no exec session with ID %s", c.ID(), sessionID)
+ }
+
+ if session.State != define.ExecStateCreated {
+ return errors.Wrapf(define.ErrExecSessionStateInvalid, "can only start created exec sessions, while container %s session %s state is %q", c.ID(), session.ID(), session.State.String())
+ }
+
+ logrus.Infof("Going to start container %s exec session %s and attach to it", c.ID(), session.ID())
+
+ opts, err := prepareForExec(c, session)
+ if err != nil {
+ return err
+ }
+
+ pid, err := c.ociRuntime.ExecContainerDetached(c, session.ID(), opts, session.Config.AttachStdin)
+ if err != nil {
+ return err
+ }
+
+ c.newContainerEvent(events.Exec)
+ logrus.Debugf("Successfully started exec session %s in container %s", session.ID(), c.ID())
+
+ // Update and save session to reflect PID/running
+ session.PID = pid
+ session.State = define.ExecStateRunning
+
+ return c.save()
}
// ExecStartAndAttach starts and attaches to an exec session in a container.
diff --git a/libpod/oci.go b/libpod/oci.go
index da4030c14..7c5218319 100644
--- a/libpod/oci.go
+++ b/libpod/oci.go
@@ -68,10 +68,10 @@ type OCIRuntime interface {
AttachResize(ctr *Container, newSize remotecommand.TerminalSize) error
// ExecContainer executes a command in a running container.
- // Returns an int (exit code), error channel (errors from attach), and
- // error (errors that occurred attempting to start the exec session).
- // This returns once the exec session is running - not once it has
- // completed, as one might expect. The attach session will remain
+ // Returns an int (PID of exec session), error channel (errors from
+ // attach), and error (errors that occurred attempting to start the exec
+ // session). This returns once the exec session is running - not once it
+ // has completed, as one might expect. The attach session will remain
// running, in a goroutine that will return via the chan error in the
// return signature.
ExecContainer(ctr *Container, sessionID string, options *ExecOptions, streams *define.AttachStreams) (int, chan error, error)
@@ -81,6 +81,10 @@ type OCIRuntime interface {
// start, with a goroutine running in the background to handle attach).
// The HTTP attach itself maintains the same invariants as HTTPAttach.
ExecContainerHTTP(ctr *Container, sessionID string, options *ExecOptions, httpConn net.Conn, httpBuf *bufio.ReadWriter, streams *HTTPAttachStreams, cancel <-chan bool) (int, chan error, error)
+ // ExecContainerDetached executes a command in a running container, but
+ // does not attach to it. Returns the PID of the exec session and an
+ // error (if starting the exec session failed)
+ ExecContainerDetached(ctr *Container, sessionID string, options *ExecOptions, stdin bool) (int, error)
// ExecAttachResize resizes the terminal of a running exec session. Only
// allowed with sessions that were created with a TTY.
ExecAttachResize(ctr *Container, sessionID string, newSize remotecommand.TerminalSize) error
diff --git a/libpod/oci_conmon_exec_linux.go b/libpod/oci_conmon_exec_linux.go
index 3fc866796..51819f90a 100644
--- a/libpod/oci_conmon_exec_linux.go
+++ b/libpod/oci_conmon_exec_linux.go
@@ -143,6 +143,49 @@ func (r *ConmonOCIRuntime) ExecContainerHTTP(ctr *Container, sessionID string, o
return pid, attachChan, err
}
+// ExecContainerDetached executes a command in a running container, but does
+// not attach to it.
+func (r *ConmonOCIRuntime) ExecContainerDetached(ctr *Container, sessionID string, options *ExecOptions, stdin bool) (int, error) {
+ if options == nil {
+ return -1, errors.Wrapf(define.ErrInvalidArg, "must provide exec options to ExecContainerHTTP")
+ }
+
+ var ociLog string
+ if logrus.GetLevel() != logrus.DebugLevel && r.supportsJSON {
+ ociLog = ctr.execOCILog(sessionID)
+ }
+
+ execCmd, pipes, err := r.startExec(ctr, sessionID, options, stdin, ociLog)
+ if err != nil {
+ return -1, err
+ }
+
+ defer func() {
+ pipes.cleanup()
+ }()
+
+ // Wait for Conmon to tell us we're ready to attach.
+ // We aren't actually *going* to attach, but this means that we're good
+ // to proceed.
+ if _, err := readConmonPipeData(pipes.attachPipe, ""); err != nil {
+ return -1, err
+ }
+
+ // Start the exec session
+ if err := writeConmonPipeData(pipes.startPipe); err != nil {
+ return -1, err
+ }
+
+ // Wait for conmon to succeed, when return.
+ if err := execCmd.Wait(); err != nil {
+ return -1, errors.Wrapf(err, "cannot run conmon")
+ }
+
+ pid, err := readConmonPipeData(pipes.syncPipe, ociLog)
+
+ return pid, err
+}
+
// ExecAttachResize resizes the TTY of the given exec session.
func (r *ConmonOCIRuntime) ExecAttachResize(ctr *Container, sessionID string, newSize remotecommand.TerminalSize) error {
controlFile, err := openControlFile(ctr, ctr.execBundlePath(sessionID))
diff --git a/libpod/oci_missing.go b/libpod/oci_missing.go
index 626740f72..4da16876c 100644
--- a/libpod/oci_missing.go
+++ b/libpod/oci_missing.go
@@ -130,6 +130,11 @@ func (r *MissingRuntime) ExecContainerHTTP(ctr *Container, sessionID string, opt
return -1, nil, r.printError()
}
+// ExecContainerDetached is not available as the runtime is missing
+func (r *MissingRuntime) ExecContainerDetached(ctr *Container, sessionID string, options *ExecOptions, stdin bool) (int, error) {
+ return -1, r.printError()
+}
+
// ExecAttachResize is not available as the runtime is missing.
func (r *MissingRuntime) ExecAttachResize(ctr *Container, sessionID string, newSize remotecommand.TerminalSize) error {
return r.printError()