diff --git a/runc/runc.go b/runc/runc.go new file mode 100644 index 0000000..198f66f --- /dev/null +++ b/runc/runc.go @@ -0,0 +1,171 @@ +// +build runc + +package runc + +import ( + "encoding/json" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + + "github.com/docker/containerd/runtime" + "github.com/opencontainers/specs" +) + +func NewRuntime(stateDir string) (runtime.Runtime, error) { + return &runcRuntime{ + stateDir: stateDir, + }, nil +} + +type runcContainer struct { + id string + path string + stateDir string + exitStatus int + processes map[int]*runcProcess + initProcess *runcProcess +} + +func (c *runcContainer) ID() string { + return c.id +} + +func (c *runcContainer) Start() error { + return c.initProcess.cmd.Start() +} + +func (c *runcContainer) Path() string { + return c.path +} + +func (c *runcContainer) Pid() (int, error) { + return c.initProcess.cmd.Process.Pid, nil +} + +func (c *runcContainer) SetExited(status int) { + c.exitStatus = status +} + +// noop for runc +func (c *runcContainer) Delete() error { + return nil +} + +func (c *runcContainer) Processes() ([]runtime.Process, error) { + procs := []runtime.Process{ + c.initProcess, + } + for _, p := range c.processes { + procs = append(procs, p) + } + return procs, nil +} + +func (c *runcContainer) RemoveProcess(pid int) error { + if _, ok := c.processes[pid]; !ok { + return runtime.ErrNotChildProcess + } + delete(c.processes, pid) + return nil +} + +func (c *runcContainer) State() runtime.State { + // TODO: how to do this with runc + return runtime.State{ + Status: runtime.Running, + } +} + +func (c *runcContainer) Resume() error { + return c.newCommand("resume").Run() +} + +func (c *runcContainer) Pause() error { + return c.newCommand("pause").Run() +} + +func (c *runcContainer) newCommand(args ...string) *exec.Cmd { + cmd := exec.Command("runc", append([]string{"--root", c.stateDir, "--id", c.id}, args...)...) + cmd.Dir = c.path + return cmd +} + +type runcProcess struct { + cmd *exec.Cmd + spec specs.Process +} + +// pid of the container, not of runc +func (p *runcProcess) Pid() (int, error) { + return p.cmd.Process.Pid, nil +} + +func (p *runcProcess) Spec() specs.Process { + return p.spec +} + +func (p *runcProcess) Signal(s os.Signal) error { + return p.cmd.Process.Signal(s) +} + +type runcRuntime struct { + stateDir string +} + +func (r *runcRuntime) Create(id, bundlePath string, stdio *runtime.Stdio) (runtime.Container, error) { + cmd := exec.Command("runc", "--root", r.stateDir, "--id", id, "start") + cmd.Dir = bundlePath + // cmd.Stderr = stdio.Stderr + // cmd.Stdout = stdio.Stdout + var s specs.Spec + f, err := os.Open(filepath.Join(bundlePath, "config.json")) + if err != nil { + return nil, err + } + defer f.Close() + if err := json.NewDecoder(f).Decode(&s); err != nil { + return nil, err + } + return &runcContainer{ + id: id, + path: bundlePath, + stateDir: r.stateDir, + initProcess: &runcProcess{ + cmd: cmd, + spec: s.Process, + }, + processes: make(map[int]*runcProcess), + }, nil +} + +func (r *runcRuntime) StartProcess(ci runtime.Container, p specs.Process, stdio *runtime.Stdio) (runtime.Process, error) { + c, ok := ci.(*runcContainer) + if !ok { + return nil, runtime.ErrInvalidContainerType + } + f, err := ioutil.TempFile("", "containerd") + if err != nil { + return nil, err + } + if err := json.NewEncoder(f).Encode(p); err != nil { + f.Close() + return nil, err + } + cmd := c.newCommand("exec", f.Name()) + f.Close() + process := &runcProcess{ + cmd: cmd, + spec: p, + } + if err := cmd.Start(); err != nil { + return nil, err + } + pid, err := process.Pid() + if err != nil { + return nil, err + } + c.processes[pid] = process + return process, nil +} diff --git a/supervisor_unsupported.go b/supervisor_unsupported.go index deca0f5..11ba385 100644 --- a/supervisor_unsupported.go +++ b/supervisor_unsupported.go @@ -3,11 +3,10 @@ package containerd import ( - "errors" - + "github.com/docker/containerd/runc" "github.com/docker/containerd/runtime" ) func newRuntime(stateDir string) (runtime.Runtime, error) { - return nil, errors.New("Unsupported runtime") + return runc.NewRuntime(stateDir) }