Add container start and supervisor

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
Michael Crosby 2016-12-05 15:38:32 -08:00
parent e620833c9e
commit 21a53c1d70
11 changed files with 380 additions and 139 deletions

View file

@ -1,14 +1,64 @@
package execution
import "fmt"
func NewContainer(stateRoot, id, bundle string) (*Container, error) {
stateDir, err := NewStateDir(stateRoot, id)
if err != nil {
return nil, err
}
return &Container{
id: id,
bundle: bundle,
stateDir: stateDir,
processes: make(map[string]Process),
}, nil
}
func LoadContainer(dir StateDir, id, bundle string, initPid int) *Container {
return &Container{
id: id,
stateDir: dir,
bundle: bundle,
initPid: initPid,
processes: make(map[string]Process),
}
}
type Container struct {
ID string
Bundle string
StateDir StateDir
id string
bundle string
stateDir StateDir
initPid int
processes map[string]Process
}
func (c *Container) AddProcess(p Process) {
func (c *Container) ID() string {
return c.id
}
func (c *Container) Bundle() string {
return c.bundle
}
func (c *Container) StateDir() StateDir {
return c.stateDir
}
func (c *Container) Wait() (uint32, error) {
for _, p := range c.processes {
if p.Pid() == c.initPid {
return p.Wait()
}
}
return nil, fmt.Errorf("no init process")
}
func (c *Container) AddProcess(p Process, isInit bool) {
if isInit {
c.initPid = p.Pid()
}
c.processes[p.ID()] = p
}

View file

@ -29,6 +29,7 @@ type Executor interface {
List() ([]*Container, error)
Load(id string) (*Container, error)
Delete(*Container) error
Start(*Container) error
StartProcess(*Container, CreateProcessOpts) (Process, error)
SignalProcess(*Container, os.Signal) error

View file

@ -29,21 +29,19 @@ type OCIRuntime struct {
runc *runc.Runc
}
func (r *OCIRuntime) Create(id string, o execution.CreateOpts) (*execution.Container, error) {
var err error
stateDir, err := NewStateDir(r.root, id)
if err != nil {
func (r *OCIRuntime) Create(id string, o execution.CreateOpts) (container *execution.Container, err error) {
if container, err = execution.NewContainer(r.root, id, o.Bundle); err != nil {
return nil, err
}
initStateDir, err := stateDir.NewProcess()
if err != nil {
return nil, err
}
// /run/runc/redis/1/pid
pidFile := filepath.Join(initStateDir, "pid")
defer func() {
if err != nil {
container.StateDir().Delete()
}
}()
var (
initDir = container.StateDir().NewProcess()
pidFile = filepath.Join(initDir, "pid")
)
err = r.runc.Create(id, o.Bundle, &runc.CreateOpts{
Pidfile: pidfile,
Stdin: o.Stdin,
@ -55,40 +53,40 @@ func (r *OCIRuntime) Create(id string, o execution.CreateOpts) (*execution.Conta
}
pid, err := runc.ReadPifFile(pidfile)
if err != nil {
// TODO: kill the container if we are going to return
return nil, err
}
process, err := newProcess(pid)
process, err := newProcess(filepath.Base(initDir), pid)
if err != nil {
return nil, err
}
container := &execution.Container{
ID: id,
Bundle: o.Bundle,
StateDir: stateDir,
}
container.AddProcess(process)
container.AddProcess(process, true)
return container, nil
}
func (r *OCIRuntime) load(runcC *runc.Container) (*execution.Container, error) {
container := &execution.Container{
ID: runcC.ID,
Bundle: runcC.Bundle,
StateDir: StateDir(filepath.Join(r.root, runcC.ID)),
}
container := execution.LoadContainer(
execution.StateDir(filepath.Join(r.root, runcC.ID)),
runcC.ID,
runcC.Bundle,
)
process, err := newProcess(runcC.Pid)
dirs, err := ioutil.ReadDir(filepath.Join(container.StateDir().Processes()))
if err != nil {
return nil, err
}
container.AddProcess(process)
// /run/containerd/container-id/processess/process-id
dirs, err := ioutil.ReadDir(filepath.Join(container.Root))
if err != nil {
return nil, err
for _, d := range dirs {
pid, err := runc.ReadPidFile(filepath.Join(d, "pid"))
if err != nil {
return nil, err
}
process, err := newProcess(filepath.Base(d), pid)
if err != nil {
return nil, err
}
container.AddProcess(process, pid == runcC.Pid)
}
return container, nil
@ -171,7 +169,7 @@ func (r *OCIRuntime) StartProcess(c *execution.Container, o CreateProcessOpts) (
return nil, err
}
container.AddProcess(process)
container.AddProcess(process, false)
return process, nil
}

View file

@ -7,20 +7,26 @@ import (
"github.com/docker/containerd/execution"
)
func newProcess(pid int) (execution.Process, error) {
func newProcess(id string, pid int) (execution.Process, error) {
proc, err := os.FindProcess(pid)
if err != nil {
return nil, err
}
return &process{
id: id,
proc: proc,
}, nil
}
type process struct {
id string
proc *os.Process
}
func (p *process) ID() string {
return p.id
}
func (p *process) Pid() int {
return p.proc.Pid
}
@ -30,6 +36,7 @@ func (p *process) Wait() (uint32, error) {
if err != nil {
return 0, nil
}
// TODO: implement kill-all if we are the init pid
return uint32(state.Sys().(syscall.WaitStatus).ExitStatus()), nil
}

View file

@ -1,18 +1,11 @@
package execution
import (
"os"
"github.com/opencontainers/runtime-spec/specs-go"
)
import "os"
type Process interface {
ID() string
Pid() int64
Spec() *specs.Process
Start() error
Status() (Status, error)
//Spec() *specs.Process
Wait() (uint32, error)
Signal(os.Signal) error
}

View file

@ -99,6 +99,14 @@ func (s *Service) Resume(ctx context.Context, r *api.ResumeContainerRequest) (*g
return nil, s.executor.Resume(container)
}
func (s *Service) Start(ctx context.Context, r *api.StartContainerRequest) (*google_protobuf.Empty, error) {
container, err := s.executor.Load(r.ID)
if err != nil {
return nil, err
}
return nil, s.executor.Start(container)
}
func (s *Service) StartProcess(ctx context.Context, r *api.StartProcessRequest) (*api.StartProcessResponse, error) {
container, err := s.executor.Load(r.ContainerId)
if err != nil {
@ -117,7 +125,6 @@ func (s *Service) StartProcess(ctx context.Context, r *api.StartProcessRequest)
if err != nil {
return nil, err
}
s.supervisor.Add(process)
return &api.StartProcessResponse{

View file

@ -12,17 +12,13 @@ type StateDir string
func NewStateDir(root, id string) (StateDir, error) {
path := filepath.Join(root, id)
err := os.Mkdir(path, 0700)
if err != nil {
if err := os.Mkdir(path, 0700); err != nil {
return "", err
}
err = os.Mkdir(filepath.Join(path, processesDir), 0700)
if err != nil {
if err := os.Mkdir(filepath.Join(path, processesDir), 0700); err != nil {
os.RemoveAll(path)
return "", err
}
return StateDir(path), err
}
@ -30,15 +26,8 @@ func (s StateDir) Delete() error {
return os.RemoveAll(string(s))
}
func (s StateDir) NewProcess(id string) (string, error) {
// TODO: generate id
newPath := filepath.Join(string(s), "1")
err := os.Mkdir(newPath, 0755)
if err != nil {
return "", err
}
return newPath, nil
func (s StateDir) NewProcess() (string, error) {
return ioutil.TempDir(s.processDir(), "")
}
func (s StateDir) ProcessDir(id string) string {
@ -46,23 +35,25 @@ func (s StateDir) ProcessDir(id string) string {
}
func (s StateDir) DeleteProcess(id string) error {
return os.RemoveAll(filepath.Join(string(s), id))
return os.RemoveAll(filepath.Join(s.processDir(), id))
}
func (s StateDir) Processes() ([]string, error) {
basepath := filepath.Join(string(s), processesDir)
dirs, err := ioutil.ReadDir(basepath)
procsDir := s.processDir()
dirs, err := ioutil.ReadDir(procsDir)
if err != nil {
return nil, err
}
paths := make([]string, 0)
for _, d := range dirs {
if d.IsDir() {
paths = append(paths, filepath.Join(basepath, d.Name()))
paths = append(paths, filepath.Join(procsDir, d.Name()))
}
}
return paths, nil
}
func (s StateDir) processDir() string {
return filepath.Join(string(s), processesDir)
}

12
execution/supervisor.go Normal file
View file

@ -0,0 +1,12 @@
package execution
type Supervisor struct {
}
type waiter interface {
Wait() (uint32, error)
}
func (s *Supervisor) Add(w waiter) {
}