Merge pull request #391 from mlaventure/restore-and-cleanup

Add restore and small cleanup
This commit is contained in:
Michael Crosby 2016-12-16 11:54:53 -08:00 committed by GitHub
commit 4171ca0ca1
15 changed files with 247 additions and 82 deletions

View file

@ -12,6 +12,15 @@ import (
"github.com/docker/containerd/execution"
)
const (
initProcessID = "init"
)
const (
PidFilename = "pid"
StartTimeFilename = "starttime"
)
var (
ErrRootEmpty = errors.New("oci: runtime root cannot be an empty string")
)
@ -59,11 +68,11 @@ func (r *OCIRuntime) Create(ctx context.Context, id string, o execution.CreateOp
}
}(container)
initProcID, initStateDir, err := container.StateDir().NewProcess()
initStateDir, err := container.StateDir().NewProcess(initProcessID)
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,
@ -79,11 +88,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(initProcID, pid)
process, err := newProcess(initProcessID, initStateDir, execution.Created)
if err != nil {
return nil, err
}
@ -112,7 +117,7 @@ func (r *OCIRuntime) load(runcC *runc.Container) (*execution.Container, error) {
execution.StateDir(filepath.Join(r.root, runcC.ID)),
runcC.ID,
runcC.Bundle,
runcC.Status,
execution.Status(runcC.Status),
int64(runcC.Pid),
)
@ -121,19 +126,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(filepath.Base(d), pid)
process, err := newProcess(filepath.Base(d), d, execution.Running)
if err != nil {
return nil, err
}
container.AddProcess(process, pid == runcC.Pid)
container.AddProcess(process, process.Pid() == int64(runcC.Pid))
}
return container, nil
@ -201,17 +198,17 @@ func (r *OCIRuntime) StartProcess(ctx context.Context, c *execution.Container, o
}
}()
procID, procStateDir, err := c.StateDir().NewProcess()
procStateDir, err := c.StateDir().NewProcess(o.ID)
if err != nil {
return nil, err
}
defer func() {
if err != nil {
c.StateDir().DeleteProcess(procID)
c.StateDir().DeleteProcess(o.ID)
}
}()
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,
@ -221,12 +218,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(procID, pid)
process, err := newProcess(o.ID, procStateDir, execution.Running)
if err != nil {
return nil, err
}

View file

@ -1,26 +1,64 @@
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(id string, pid int) (execution.Process, error) {
proc, err := os.FindProcess(pid)
func newProcess(id, stateDir string, status execution.Status) (execution.Process, error) {
pid, err := runc.ReadPidFile(filepath.Join(stateDir, PidFilename))
if err != nil {
return nil, err
}
if err := syscall.Kill(pid, 0); err != nil {
if err == syscall.ESRCH {
status = execution.Stopped
} else {
return nil, err
}
}
if status != execution.Stopped {
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{
id: id,
proc: proc,
id: id,
pid: pid,
status: status,
exitCode: execution.UnknownStatusCode,
}, nil
}
type process struct {
id string
proc *os.Process
id string
pid int
status execution.Status
exitCode uint32
}
func (p *process) ID() string {
@ -28,18 +66,37 @@ func (p *process) ID() string {
}
func (p *process) Pid() int64 {
return int64(p.proc.Pid)
return int64(p.pid)
}
func (p *process) Wait() (uint32, error) {
state, err := p.proc.Wait()
if err != nil {
return 0, nil
if p.status != execution.Stopped {
var wstatus syscall.WaitStatus
_, err := syscall.Wait4(p.pid, &wstatus, 0, nil)
if err != nil {
// This process doesn't belong to us
p.exitCode = execution.UnknownStatusCode
return p.exitCode, nil
}
// TODO: implement kill-all if we are the init pid?
p.status = execution.Stopped
p.exitCode = uint32(wstatus.ExitStatus())
}
// TODO: implement kill-all if we are the init pid
return uint32(state.Sys().(syscall.WaitStatus).ExitStatus()), nil
return p.exitCode, nil
}
func (p *process) Signal(s os.Signal) error {
return p.proc.Signal(s)
if p.status != execution.Stopped {
sig, ok := s.(syscall.Signal)
if !ok {
return fmt.Errorf("invalid signal %v", s)
}
return syscall.Kill(p.pid, sig)
}
return execution.ErrProcessNotFound
}
func (p *process) Status() execution.Status {
return p.status
}