Esempio n. 1
0
func (d *directProcess) watch(cmd *exec.Cmd, exitSubscription *subreaper.Subscription) {
	defer subreaper.Unsubscribe(exitSubscription)
	defer d.delete()

	f, err := os.OpenFile(path.Join(d.root, ExitFile), syscall.O_WRONLY, 0)
	if err == nil {
		defer f.Close()
	}

	exitCode := 0
	if err = cmd.Wait(); err != nil {
		if exitError, ok := err.(exec.ExitCodeError); ok {
			exitCode = exitError.Code
		}
	}

	if exitCode == 0 {
		pid, err := d.getPidFromFile()
		if err != nil {
			return
		}
		exitSubscription.SetPid(pid)
		exitCode = exitSubscription.Wait()
	}

	writeInt(path.Join(d.root, ExitStatusFile), exitCode)
}
Esempio n. 2
0
func (p *process) startCmd(cmd *exec.Cmd) error {
	if err := cmd.Start(); err != nil {
		if exErr, ok := err.(*exec.Error); ok {
			if exErr.Err == exec.ErrNotFound || exErr.Err == os.ErrNotExist {
				return fmt.Errorf("%s not installed on system", p.container.shim)
			}
		}
		return err
	}
	if err := p.waitForStart(cmd); err != nil {
		return err
	}
	return nil
}
Esempio n. 3
0
// cmdStream executes a command, and returns its stdout as a stream.
// If the command fails to run or doesn't complete successfully, an error
// will be returned, including anything written on stderr.
func cmdStream(cmd *exec.Cmd, input io.Reader) (io.ReadCloser, <-chan struct{}, error) {
	chdone := make(chan struct{})
	cmd.Stdin = input
	pipeR, pipeW := io.Pipe()
	cmd.Stdout = pipeW
	var errBuf bytes.Buffer
	cmd.Stderr = &errBuf

	// Run the command and return the pipe
	if err := cmd.Start(); err != nil {
		return nil, nil, err
	}

	// Copy stdout to the returned pipe
	go func() {
		if err := cmd.Wait(); err != nil {
			pipeW.CloseWithError(fmt.Errorf("%s: %s", err, errBuf.String()))
		} else {
			pipeW.Close()
		}
		close(chdone)
	}()

	return pipeR, chdone, nil
}
Esempio n. 4
0
func (p *process) waitForStart(cmd *exec.Cmd) error {
	wc := make(chan error, 1)
	go func() {
		for {
			if _, err := p.getPidFromFile(); err != nil {
				if os.IsNotExist(err) || err == errInvalidPidInt {
					alive, err := isAlive(cmd)
					if err != nil {
						wc <- err
						return
					}
					if !alive {
						// runc could have failed to run the container so lets get the error
						// out of the logs or the shim could have encountered an error
						messages, err := readLogMessages(filepath.Join(p.root, "shim-log.json"))
						if err != nil && !os.IsNotExist(err) {
							wc <- err
							return
						}
						for _, m := range messages {
							if m.Level == "error" {
								wc <- fmt.Errorf("shim error: %v", m.Msg)
								return
							}
						}
						// no errors reported back from shim, check for runc/runtime errors
						messages, err = readLogMessages(filepath.Join(p.root, "log.json"))
						if err != nil {
							if os.IsNotExist(err) {
								err = ErrContainerNotStarted
							}
							wc <- err
							return
						}
						for _, m := range messages {
							if m.Level == "error" {
								wc <- fmt.Errorf("oci runtime error: %v", m.Msg)
								return
							}
						}
						wc <- ErrContainerNotStarted
						return
					}
					time.Sleep(15 * time.Millisecond)
					continue
				}
				wc <- err
				return
			}
			// the pid file was read successfully
			wc <- nil
			return
		}
	}()
	select {
	case err := <-wc:
		if err != nil {
			return err
		}
		return nil
	case <-time.After(p.container.timeout):
		cmd.Process.Kill()
		cmd.Wait()
		return ErrContainerStartTimeout
	}
}