execution/oci: Add check when loading processes

This should ensure that we don't kill a different process after a
restore (once supported)

Signed-off-by: Kenfe-Mickael Laventure <mickael.laventure@gmail.com>
This commit is contained in:
Kenfe-Mickael Laventure 2016-12-15 08:21:04 -08:00
parent abaa421141
commit 73cb78fae3
2 changed files with 42 additions and 23 deletions

View file

@ -16,6 +16,11 @@ const (
initProcessID = "init" initProcessID = "init"
) )
const (
PidFilename = "pid"
StartTimeFilename = "starttime"
)
var ( var (
ErrRootEmpty = errors.New("oci: runtime root cannot be an empty string") 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 { if err != nil {
return nil, err return nil, err
} }
pidFile := filepath.Join(initStateDir, "pid") pidFile := filepath.Join(initStateDir, PidFilename)
err = r.runc.Create(ctx, id, o.Bundle, &runc.CreateOpts{ err = r.runc.Create(ctx, id, o.Bundle, &runc.CreateOpts{
PidFile: pidFile, PidFile: pidFile,
Console: oio.console, Console: oio.console,
@ -80,11 +85,7 @@ func (r *OCIRuntime) Create(ctx context.Context, id string, o execution.CreateOp
} }
}() }()
pid, err := runc.ReadPidFile(pidFile) process, err := newProcess(container, initProcessID, initStateDir)
if err != nil {
return nil, err
}
process, err := newProcess(container, initProcessID, pid)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -122,19 +123,11 @@ func (r *OCIRuntime) load(runcC *runc.Container) (*execution.Container, error) {
return nil, err return nil, err
} }
for _, d := range dirs { for _, d := range dirs {
pid, err := runc.ReadPidFile(filepath.Join(d, "pid")) process, err := newProcess(container, filepath.Base(d), d)
if err != nil {
if os.IsNotExist(err) {
// Process died in between
continue
}
return nil, err
}
process, err := newProcess(container, filepath.Base(d), pid)
if err != nil { if err != nil {
return nil, err return nil, err
} }
container.AddProcess(process, pid == runcC.Pid) container.AddProcess(process, process.Pid() == int64(runcC.Pid))
} }
return container, nil 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{ if err := r.runc.Exec(ctx, c.ID(), o.Spec, &runc.ExecOpts{
PidFile: pidFile, PidFile: pidFile,
Detach: false, Detach: false,
@ -222,12 +215,8 @@ func (r *OCIRuntime) StartProcess(ctx context.Context, c *execution.Container, o
}); err != nil { }); err != nil {
return nil, err 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 { if err != nil {
return nil, err return nil, err
} }

View file

@ -2,13 +2,21 @@ package oci
import ( import (
"fmt" "fmt"
"io/ioutil"
"os" "os"
"path/filepath"
"syscall" "syscall"
"github.com/crosbymichael/go-runc"
"github.com/docker/containerd/execution" "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 status := execution.Running
if err := syscall.Kill(pid, 0); err != nil { if err := syscall.Kill(pid, 0); err != nil {
if err == syscall.ESRCH { if err == syscall.ESRCH {
@ -17,6 +25,28 @@ func newProcess(c *execution.Container, id string, pid int) (execution.Process,
return nil, err 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{ return &process{
c: c, c: c,
id: id, id: id,