diff --git a/execution/executors/oci/oci.go b/execution/executors/oci/oci.go index 98c78e714..07d449059 100644 --- a/execution/executors/oci/oci.go +++ b/execution/executors/oci/oci.go @@ -16,6 +16,11 @@ const ( initProcessID = "init" ) +const ( + PidFilename = "pid" + StartTimeFilename = "starttime" +) + var ( ErrRootEmpty = errors.New("oci: runtime root cannot be an empty string") ) @@ -64,7 +69,7 @@ func (r *OCIRuntime) Create(ctx context.Context, id string, o execution.CreateOp if err != nil { return nil, err } - pidFile := filepath.Join(initStateDir, "pid") + pidFile := filepath.Join(initStateDir, PidFilename) err = r.runc.Create(ctx, id, o.Bundle, &runc.CreateOpts{ PidFile: pidFile, Console: oio.console, @@ -80,11 +85,7 @@ func (r *OCIRuntime) Create(ctx context.Context, id string, o execution.CreateOp } }() - pid, err := runc.ReadPidFile(pidFile) - if err != nil { - return nil, err - } - process, err := newProcess(container, initProcessID, pid) + process, err := newProcess(container, initProcessID, initStateDir) if err != nil { return nil, err } @@ -122,19 +123,11 @@ func (r *OCIRuntime) load(runcC *runc.Container) (*execution.Container, error) { return nil, err } for _, d := range dirs { - pid, err := runc.ReadPidFile(filepath.Join(d, "pid")) - if err != nil { - if os.IsNotExist(err) { - // Process died in between - continue - } - return nil, err - } - process, err := newProcess(container, filepath.Base(d), pid) + process, err := newProcess(container, filepath.Base(d), d) if err != nil { return nil, err } - container.AddProcess(process, pid == runcC.Pid) + container.AddProcess(process, process.Pid() == int64(runcC.Pid)) } return container, nil @@ -212,7 +205,7 @@ func (r *OCIRuntime) StartProcess(ctx context.Context, c *execution.Container, o } }() - pidFile := filepath.Join(procStateDir, "pid") + pidFile := filepath.Join(procStateDir, PidFilename) if err := r.runc.Exec(ctx, c.ID(), o.Spec, &runc.ExecOpts{ PidFile: pidFile, Detach: false, @@ -222,12 +215,8 @@ func (r *OCIRuntime) StartProcess(ctx context.Context, c *execution.Container, o }); err != nil { return nil, err } - pid, err := runc.ReadPidFile(pidFile) - if err != nil { - return nil, err - } - process, err := newProcess(c, o.ID, pid) + process, err := newProcess(c, o.ID, procStateDir) if err != nil { return nil, err } diff --git a/execution/executors/oci/process.go b/execution/executors/oci/process.go index 53a4a5330..b3f73f881 100644 --- a/execution/executors/oci/process.go +++ b/execution/executors/oci/process.go @@ -2,13 +2,21 @@ package oci import ( "fmt" + "io/ioutil" "os" + "path/filepath" "syscall" + "github.com/crosbymichael/go-runc" "github.com/docker/containerd/execution" + starttime "github.com/opencontainers/runc/libcontainer/system" ) -func newProcess(c *execution.Container, id string, pid int) (execution.Process, error) { +func newProcess(c *execution.Container, id, stateDir string) (execution.Process, error) { + pid, err := runc.ReadPidFile(filepath.Join(stateDir, PidFilename)) + if err != nil { + return nil, err + } status := execution.Running if err := syscall.Kill(pid, 0); err != nil { if err == syscall.ESRCH { @@ -17,6 +25,28 @@ func newProcess(c *execution.Container, id string, pid int) (execution.Process, return nil, err } } + if status == execution.Running { + stime, err := starttime.GetProcessStartTime(pid) + switch { + case os.IsNotExist(err): + status = execution.Stopped + case err != nil: + return nil, err + default: + b, err := ioutil.ReadFile(filepath.Join(stateDir, StartTimeFilename)) + switch { + case os.IsNotExist(err): + err = ioutil.WriteFile(filepath.Join(stateDir, StartTimeFilename), []byte(stime), 0600) + if err != nil { + return nil, err + } + case err != nil: + return nil, err + case string(b) != stime: + status = execution.Stopped + } + } + } return &process{ c: c, id: id,