fe38efda50
Signed-off-by: Michael Crosby <crosbymichael@gmail.com> Remove runtime files from containerd Signed-off-by: Michael Crosby <crosbymichael@gmail.com> Update supervisor for orphaned containers Signed-off-by: Michael Crosby <crosbymichael@gmail.com> Remove ctr/container.go back to rpc calls Signed-off-by: Michael Crosby <crosbymichael@gmail.com> Add attach to loaded container Signed-off-by: Michael Crosby <crosbymichael@gmail.com> Add monitor based on epoll for process exits Signed-off-by: Michael Crosby <crosbymichael@gmail.com> Convert pids in containerd to string This is so that we no longer care about linux or system level pids and processes in containerd have user defined process id(pid) kinda like the exec process ids that docker has today. Signed-off-by: Michael Crosby <crosbymichael@gmail.com> Add reaper back to containerd Signed-off-by: Michael Crosby <crosbymichael@gmail.com> Implement list containers with new process model Signed-off-by: Michael Crosby <crosbymichael@gmail.com> Implement restore of processes Signed-off-by: Michael Crosby <crosbymichael@gmail.com> Add NONBLOCK to exit fifo open Signed-off-by: Michael Crosby <crosbymichael@gmail.com> Implement tty reattach Signed-off-by: Michael Crosby <crosbymichael@gmail.com> Fix race in exit pipe creation Signed-off-by: Michael Crosby <crosbymichael@gmail.com> Add delete to shim Signed-off-by: Michael Crosby <crosbymichael@gmail.com> Update shim to use pid-file and not stdout Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
172 lines
3.6 KiB
Go
172 lines
3.6 KiB
Go
package runtime
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io/ioutil"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"syscall"
|
|
|
|
"github.com/Sirupsen/logrus"
|
|
"github.com/opencontainers/specs"
|
|
)
|
|
|
|
const (
|
|
ExitFile = "exit"
|
|
ExitStatusFile = "exitStatus"
|
|
StateFile = "state.json"
|
|
InitProcessID = "init"
|
|
)
|
|
|
|
type state struct {
|
|
Bundle string `json:"bundle"`
|
|
}
|
|
|
|
// New returns a new container
|
|
func New(root, id, bundle string) (Container, error) {
|
|
c := &container{
|
|
root: root,
|
|
id: id,
|
|
bundle: bundle,
|
|
processes: make(map[string]*process),
|
|
}
|
|
if err := os.Mkdir(filepath.Join(root, id), 0755); err != nil {
|
|
return nil, err
|
|
}
|
|
f, err := os.Create(filepath.Join(root, id, StateFile))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer f.Close()
|
|
if err := json.NewEncoder(f).Encode(state{
|
|
Bundle: bundle,
|
|
}); err != nil {
|
|
return nil, err
|
|
}
|
|
return c, nil
|
|
}
|
|
|
|
func Load(root, id string) (Container, error) {
|
|
var s state
|
|
f, err := os.Open(filepath.Join(root, id, StateFile))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer f.Close()
|
|
if err := json.NewDecoder(f).Decode(&s); err != nil {
|
|
return nil, err
|
|
}
|
|
c := &container{
|
|
root: root,
|
|
id: id,
|
|
bundle: s.Bundle,
|
|
processes: make(map[string]*process),
|
|
}
|
|
dirs, err := ioutil.ReadDir(filepath.Join(root, id))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, d := range dirs {
|
|
if !d.IsDir() {
|
|
continue
|
|
}
|
|
pid := d.Name()
|
|
// TODO: get the process spec from a state file in the process dir
|
|
p, err := loadProcess(filepath.Join(root, id, pid), pid, c, specs.Process{})
|
|
if err != nil {
|
|
if err == ErrProcessExited {
|
|
logrus.WithField("id", id).WithField("pid", pid).Debug("containerd: process exited while away")
|
|
// TODO: fire events to do the removal
|
|
if err := os.RemoveAll(filepath.Join(root, id, pid)); err != nil {
|
|
logrus.WithField("error", err).Warn("containerd: remove process state")
|
|
}
|
|
continue
|
|
}
|
|
return nil, err
|
|
}
|
|
c.processes[pid] = p
|
|
}
|
|
if len(c.processes) == 0 {
|
|
return nil, ErrContainerExited
|
|
}
|
|
return c, nil
|
|
}
|
|
|
|
type container struct {
|
|
// path to store runtime state information
|
|
root string
|
|
id string
|
|
bundle string
|
|
processes map[string]*process
|
|
}
|
|
|
|
func (c *container) ID() string {
|
|
return c.id
|
|
}
|
|
|
|
func (c *container) Path() string {
|
|
return c.bundle
|
|
}
|
|
|
|
func (c *container) Start() (Process, error) {
|
|
processRoot := filepath.Join(c.root, c.id, InitProcessID)
|
|
if err := os.MkdirAll(processRoot, 0755); err != nil {
|
|
return nil, err
|
|
}
|
|
cmd := exec.Command("containerd-shim", processRoot, c.id)
|
|
cmd.Dir = c.bundle
|
|
cmd.SysProcAttr = &syscall.SysProcAttr{
|
|
Setpgid: true,
|
|
}
|
|
spec, err := c.readSpec()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
p, err := newProcess(processRoot, InitProcessID, c, spec.Process)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if err := cmd.Start(); err != nil {
|
|
return nil, err
|
|
}
|
|
c.processes[InitProcessID] = p
|
|
return p, nil
|
|
}
|
|
|
|
func (c *container) readSpec() (*specs.LinuxSpec, error) {
|
|
var spec specs.LinuxSpec
|
|
f, err := os.Open(filepath.Join(c.bundle, "config.json"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer f.Close()
|
|
if err := json.NewDecoder(f).Decode(&spec); err != nil {
|
|
return nil, err
|
|
}
|
|
return &spec, nil
|
|
}
|
|
|
|
func (c *container) Pause() error {
|
|
return errNotImplemented
|
|
}
|
|
|
|
func (c *container) Resume() error {
|
|
return errNotImplemented
|
|
}
|
|
|
|
func (c *container) State() State {
|
|
return Running
|
|
}
|
|
|
|
func (c *container) Delete() error {
|
|
return os.RemoveAll(filepath.Join(c.root, c.id))
|
|
}
|
|
|
|
func (c *container) Processes() ([]Process, error) {
|
|
out := []Process{}
|
|
for _, p := range c.processes {
|
|
out = append(out, p)
|
|
}
|
|
return out, nil
|
|
}
|