Refactor process.go for platform specific
Signed-off-by: John Howard <jhoward@microsoft.com> Move process sorter to new file Signed-off-by: Michael Crosby <crosbymichael@gmail.com> Sort containers by id This will not be the most accurate sorting but atleast the list will be consistent inbetween calls. Signed-off-by: Michael Crosby <crosbymichael@gmail.com> Allow runtime to be configurable via daemon start This allows people to pass an alternate name or location to the runtime binary to start containers. Signed-off-by: Michael Crosby <crosbymichael@gmail.com> Fix state output for containers Return the proper state/status for a container by checking if the pid is still alive. Also fix the cleanup handling in the shim to make sure containers are not left behind. Signed-off-by: Michael Crosby <crosbymichael@gmail.com> Properly wait for container start Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
parent
0ad7654f80
commit
b044ff0f29
19 changed files with 323 additions and 206 deletions
|
@ -5,6 +5,7 @@ import (
|
|||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
@ -42,6 +43,8 @@ type Container interface {
|
|||
Pids() ([]int, error)
|
||||
// Stats returns realtime container stats and resource information
|
||||
Stats() (*Stat, error)
|
||||
// Name or path of the OCI compliant runtime used to execute the container
|
||||
Runtime() string
|
||||
// OOM signals the channel if the container received an OOM notification
|
||||
// OOM() (<-chan struct{}, error)
|
||||
}
|
||||
|
@ -68,13 +71,14 @@ func NewStdio(stdin, stdout, stderr string) Stdio {
|
|||
}
|
||||
|
||||
// New returns a new container
|
||||
func New(root, id, bundle string, labels []string) (Container, error) {
|
||||
func New(root, id, bundle, runtimeName string, labels []string) (Container, error) {
|
||||
c := &container{
|
||||
root: root,
|
||||
id: id,
|
||||
bundle: bundle,
|
||||
labels: labels,
|
||||
processes: make(map[string]*process),
|
||||
runtime: runtimeName,
|
||||
}
|
||||
if err := os.Mkdir(filepath.Join(root, id), 0755); err != nil {
|
||||
return nil, err
|
||||
|
@ -85,8 +89,9 @@ func New(root, id, bundle string, labels []string) (Container, error) {
|
|||
}
|
||||
defer f.Close()
|
||||
if err := json.NewEncoder(f).Encode(state{
|
||||
Bundle: bundle,
|
||||
Labels: labels,
|
||||
Bundle: bundle,
|
||||
Labels: labels,
|
||||
Runtime: runtimeName,
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -108,6 +113,7 @@ func Load(root, id string) (Container, error) {
|
|||
id: id,
|
||||
bundle: s.Bundle,
|
||||
labels: s.Labels,
|
||||
runtime: s.Runtime,
|
||||
processes: make(map[string]*process),
|
||||
}
|
||||
dirs, err := ioutil.ReadDir(filepath.Join(root, id))
|
||||
|
@ -151,6 +157,7 @@ type container struct {
|
|||
root string
|
||||
id string
|
||||
bundle string
|
||||
runtime string
|
||||
processes map[string]*process
|
||||
stdio Stdio
|
||||
labels []string
|
||||
|
@ -182,6 +189,14 @@ func (c *container) readSpec() (*PlatformSpec, error) {
|
|||
}
|
||||
|
||||
func (c *container) State() State {
|
||||
proc := c.processes["init"]
|
||||
if proc == nil || proc.pid == 0 {
|
||||
return Stopped
|
||||
}
|
||||
err := syscall.Kill(proc.pid, 0)
|
||||
if err != nil && err == syscall.ESRCH {
|
||||
return Stopped
|
||||
}
|
||||
return Running
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,10 @@ func getRootIDs(s *PlatformSpec) (int, int, error) {
|
|||
return uid, gid, nil
|
||||
}
|
||||
|
||||
func (c *container) Runtime() string {
|
||||
return c.runtime
|
||||
}
|
||||
|
||||
func (c *container) Pause() error {
|
||||
return exec.Command("runc", "pause", c.id).Run()
|
||||
}
|
||||
|
@ -115,7 +119,7 @@ func (c *container) Start(checkpoint string, s Stdio) (Process, error) {
|
|||
return nil, err
|
||||
}
|
||||
cmd := exec.Command("containerd-shim",
|
||||
c.id, c.bundle,
|
||||
c.id, c.bundle, c.runtime,
|
||||
)
|
||||
cmd.Dir = processRoot
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{
|
||||
|
@ -141,8 +145,8 @@ func (c *container) Start(checkpoint string, s Stdio) (Process, error) {
|
|||
if err := cmd.Start(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := p.getPid(); err != nil {
|
||||
return p, nil
|
||||
if err := waitForStart(p, cmd); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.processes[InitProcessID] = p
|
||||
return p, nil
|
||||
|
@ -154,7 +158,7 @@ func (c *container) Exec(pid string, spec ProcessSpec, s Stdio) (Process, error)
|
|||
return nil, err
|
||||
}
|
||||
cmd := exec.Command("containerd-shim",
|
||||
c.id, c.bundle,
|
||||
c.id, c.bundle, c.runtime,
|
||||
)
|
||||
cmd.Dir = processRoot
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{
|
||||
|
@ -175,8 +179,8 @@ func (c *container) Exec(pid string, spec ProcessSpec, s Stdio) (Process, error)
|
|||
if err := cmd.Start(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := p.getPid(); err != nil {
|
||||
return p, nil
|
||||
if err := waitForStart(p, cmd); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.processes[pid] = p
|
||||
return p, nil
|
||||
|
@ -222,3 +226,34 @@ func (c *container) Stats() (*Stat, error) {
|
|||
Data: stats,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func waitForStart(p *process, cmd *exec.Cmd) error {
|
||||
for i := 0; i < 50; i++ {
|
||||
if _, err := p.getPidFromFile(); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
alive, err := isAlive(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !alive {
|
||||
return ErrContainerNotStarted
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return errNoPidFile
|
||||
}
|
||||
|
||||
func isAlive(cmd *exec.Cmd) (bool, error) {
|
||||
if err := syscall.Kill(cmd.Process.Pid, 0); err != nil {
|
||||
if err == syscall.ESRCH {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
|
|
@ -6,6 +6,10 @@ func getRootIDs(s *PlatformSpec) (int, int, error) {
|
|||
return 0, 0, nil
|
||||
}
|
||||
|
||||
func (c *container) Runtime() string {
|
||||
return "windows"
|
||||
}
|
||||
|
||||
func (c *container) Pause() error {
|
||||
return errors.New("Pause not supported on Windows")
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Process interface {
|
||||
|
@ -95,7 +94,7 @@ func loadProcess(root, id string, c *container, s *ProcessState) (*process, erro
|
|||
Stderr: s.Stderr,
|
||||
},
|
||||
}
|
||||
if _, err := p.getPid(); err != nil {
|
||||
if _, err := p.getPidFromFile(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := p.ExitStatus(); err != nil {
|
||||
|
@ -177,22 +176,15 @@ func (p *process) Close() error {
|
|||
return p.exitPipe.Close()
|
||||
}
|
||||
|
||||
func (p *process) getPid() (int, error) {
|
||||
for i := 0; i < 20; i++ {
|
||||
data, err := ioutil.ReadFile(filepath.Join(p.root, "pid"))
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
return -1, err
|
||||
}
|
||||
i, err := strconv.Atoi(string(data))
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
p.pid = i
|
||||
return i, nil
|
||||
func (p *process) getPidFromFile() (int, error) {
|
||||
data, err := ioutil.ReadFile(filepath.Join(p.root, "pid"))
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return -1, fmt.Errorf("containerd: cannot read pid file")
|
||||
i, err := strconv.Atoi(string(data))
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
p.pid = i
|
||||
return i, nil
|
||||
}
|
||||
|
|
|
@ -14,7 +14,9 @@ var (
|
|||
ErrTerminalsNotSupported = errors.New("containerd: terminals are not supported for runtime")
|
||||
ErrProcessNotExited = errors.New("containerd: process has not exited")
|
||||
ErrProcessExited = errors.New("containerd: process has exited")
|
||||
ErrContainerNotStarted = errors.New("containerd: container not started")
|
||||
|
||||
errNoPidFile = errors.New("containerd: no process pid file found")
|
||||
errNotImplemented = errors.New("containerd: not implemented")
|
||||
)
|
||||
|
||||
|
@ -30,15 +32,17 @@ type State string
|
|||
|
||||
const (
|
||||
Paused = State("paused")
|
||||
Stopped = State("stopped")
|
||||
Running = State("running")
|
||||
)
|
||||
|
||||
type state struct {
|
||||
Bundle string `json:"bundle"`
|
||||
Labels []string `json:"labels"`
|
||||
Stdin string `json:"stdin"`
|
||||
Stdout string `json:"stdout"`
|
||||
Stderr string `json:"stderr"`
|
||||
Bundle string `json:"bundle"`
|
||||
Labels []string `json:"labels"`
|
||||
Stdin string `json:"stdin"`
|
||||
Stdout string `json:"stdout"`
|
||||
Stderr string `json:"stderr"`
|
||||
Runtime string `json:"runtime"`
|
||||
}
|
||||
|
||||
type ProcessState struct {
|
||||
|
|
|
@ -2,5 +2,7 @@ package runtime
|
|||
|
||||
import "github.com/opencontainers/specs"
|
||||
|
||||
type PlatformSpec specs.LinuxSpec
|
||||
type ProcessSpec specs.Process
|
||||
type (
|
||||
PlatformSpec specs.LinuxSpec
|
||||
ProcessSpec specs.Process
|
||||
)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue