diff options
Diffstat (limited to 'libpod/oci_conmon_linux.go')
-rw-r--r-- | libpod/oci_conmon_linux.go | 82 |
1 files changed, 54 insertions, 28 deletions
diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go index 800f89603..8da6db09f 100644 --- a/libpod/oci_conmon_linux.go +++ b/libpod/oci_conmon_linux.go @@ -595,31 +595,29 @@ func (r *ConmonOCIRuntime) AttachResize(ctr *Container, newSize remotecommand.Te // ExecContainer executes a command in a running container // TODO: Split into Create/Start/Attach/Wait -func (r *ConmonOCIRuntime) ExecContainer(c *Container, sessionID string, options *ExecOptions) (int, chan error, error) { +func (r *ConmonOCIRuntime) ExecContainer(c *Container, sessionID string, options *ExecOptions) (chan DataAndErr, chan error, error) { if options == nil { - return -1, nil, errors.Wrapf(define.ErrInvalidArg, "must provide an ExecOptions struct to ExecContainer") + return nil, nil, errors.Wrapf(define.ErrInvalidArg, "must provide an ExecOptions struct to ExecContainer") } if len(options.Cmd) == 0 { - return -1, nil, errors.Wrapf(define.ErrInvalidArg, "must provide a command to execute") + return nil, nil, errors.Wrapf(define.ErrInvalidArg, "must provide a command to execute") } if sessionID == "" { - return -1, nil, errors.Wrapf(define.ErrEmptyID, "must provide a session ID for exec") + return nil, nil, errors.Wrapf(define.ErrEmptyID, "must provide a session ID for exec") } // create sync pipe to receive the pid parentSyncPipe, childSyncPipe, err := newPipe() if err != nil { - return -1, nil, errors.Wrapf(err, "error creating socket pair") + return nil, nil, errors.Wrapf(err, "error creating socket pair") } - defer errorhandling.CloseQuiet(parentSyncPipe) - // create start pipe to set the cgroup before running // attachToExec is responsible for closing parentStartPipe childStartPipe, parentStartPipe, err := newPipe() if err != nil { - return -1, nil, errors.Wrapf(err, "error creating socket pair") + return nil, nil, errors.Wrapf(err, "error creating socket pair") } // We want to make sure we close the parent{Start,Attach}Pipes if we fail @@ -638,7 +636,7 @@ func (r *ConmonOCIRuntime) ExecContainer(c *Container, sessionID string, options // attachToExec is responsible for closing parentAttachPipe parentAttachPipe, childAttachPipe, err := newPipe() if err != nil { - return -1, nil, errors.Wrapf(err, "error creating socket pair") + return nil, nil, errors.Wrapf(err, "error creating socket pair") } defer func() { @@ -658,7 +656,7 @@ func (r *ConmonOCIRuntime) ExecContainer(c *Container, sessionID string, options runtimeDir, err := util.GetRuntimeDir() if err != nil { - return -1, nil, err + return nil, nil, err } finalEnv := make([]string, 0, len(options.Env)) @@ -668,7 +666,7 @@ func (r *ConmonOCIRuntime) ExecContainer(c *Container, sessionID string, options processFile, err := prepareProcessExec(c, options.Cmd, finalEnv, options.Terminal, options.Cwd, options.User, sessionID) if err != nil { - return -1, nil, err + return nil, nil, err } var ociLog string @@ -717,7 +715,7 @@ func (r *ConmonOCIRuntime) ExecContainer(c *Container, sessionID string, options conmonEnv, extraFiles, err := r.configureConmonEnv(runtimeDir) if err != nil { - return -1, nil, err + return nil, nil, err } if options.PreserveFDs > 0 { @@ -748,10 +746,10 @@ func (r *ConmonOCIRuntime) ExecContainer(c *Container, sessionID string, options childrenClosed = true if err != nil { - return -1, nil, errors.Wrapf(err, "cannot start container %s", c.ID()) + return nil, nil, errors.Wrapf(err, "cannot start container %s", c.ID()) } if err := r.moveConmonToCgroupAndSignal(c, execCmd, parentStartPipe); err != nil { - return -1, nil, err + return nil, nil, err } if options.PreserveFDs > 0 { @@ -774,9 +772,16 @@ func (r *ConmonOCIRuntime) ExecContainer(c *Container, sessionID string, options }() attachToExecCalled = true - pid, err := readConmonPipeData(parentSyncPipe, ociLog) + dataChan := make(chan DataAndErr) + go func() { + // read the exec pid + dataChan <- readConmonPipeData(parentSyncPipe, ociLog) + // read the exec exit code + dataChan <- readConmonPipeData(parentSyncPipe, ociLog) + errorhandling.CloseQuiet(parentSyncPipe) + }() - return pid, attachChan, err + return dataChan, attachChan, err } // ExecStopContainer stops a given exec session in a running container. @@ -1206,14 +1211,14 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co return err } - pid, err := readConmonPipeData(parentSyncPipe, ociLog) - if err != nil { + pipeData := readConmonPipeData(parentSyncPipe, ociLog) + if pipeData.err != nil { if err2 := r.DeleteContainer(ctr); err2 != nil { logrus.Errorf("Error removing container %s from runtime after creation failed", ctr.ID()) } - return err + return pipeData.err } - ctr.state.PID = pid + ctr.state.PID = pipeData.data conmonPID, err := readConmonPidFile(ctr.config.ConmonPidFile) if err != nil { @@ -1525,7 +1530,7 @@ func readConmonPidFile(pidFile string) (int, error) { } // readConmonPipeData attempts to read a syncInfo struct from the pipe -func readConmonPipeData(pipe *os.File, ociLog string) (int, error) { +func readConmonPipeData(pipe *os.File, ociLog string) DataAndErr { // syncInfo is used to return data from monitor process to daemon type syncInfo struct { Data int `json:"data"` @@ -1561,11 +1566,17 @@ func readConmonPipeData(pipe *os.File, ociLog string) (int, error) { if err == nil { var ociErr ociError if err := json.Unmarshal(ociLogData, &ociErr); err == nil { - return -1, getOCIRuntimeError(ociErr.Msg) + return DataAndErr{ + data: -1, + err: getOCIRuntimeError(ociErr.Msg), + } } } } - return -1, errors.Wrapf(ss.err, "container create failed (no logs from conmon)") + return DataAndErr{ + data: -1, + err: errors.Wrapf(ss.err, "container create failed (no logs from conmon)"), + } } logrus.Debugf("Received: %d", ss.si.Data) if ss.si.Data < 0 { @@ -1574,21 +1585,36 @@ func readConmonPipeData(pipe *os.File, ociLog string) (int, error) { if err == nil { var ociErr ociError if err := json.Unmarshal(ociLogData, &ociErr); err == nil { - return ss.si.Data, getOCIRuntimeError(ociErr.Msg) + return DataAndErr{ + data: ss.si.Data, + err: getOCIRuntimeError(ociErr.Msg), + } } } } // If we failed to parse the JSON errors, then print the output as it is if ss.si.Message != "" { - return ss.si.Data, getOCIRuntimeError(ss.si.Message) + return DataAndErr{ + data: ss.si.Data, + err: getOCIRuntimeError(ss.si.Message), + } + } + return DataAndErr{ + data: ss.si.Data, + err: errors.Wrapf(define.ErrInternal, "container create failed"), } - return ss.si.Data, errors.Wrapf(define.ErrInternal, "container create failed") } data = ss.si.Data case <-time.After(define.ContainerCreateTimeout): - return -1, errors.Wrapf(define.ErrInternal, "container creation timeout") + return DataAndErr{ + data: -1, + err: errors.Wrapf(define.ErrInternal, "container creation timeout"), + } + } + return DataAndErr{ + data: data, + err: nil, } - return data, nil } // writeConmonPipeData writes nonse data to a pipe |