Add container start and supervisor
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
parent
e620833c9e
commit
21a53c1d70
11 changed files with 380 additions and 139 deletions
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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
12
execution/supervisor.go
Normal file
|
@ -0,0 +1,12 @@
|
|||
package execution
|
||||
|
||||
type Supervisor struct {
|
||||
}
|
||||
|
||||
type waiter interface {
|
||||
Wait() (uint32, error)
|
||||
}
|
||||
|
||||
func (s *Supervisor) Add(w waiter) {
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue