Refactor windows runtime

Signed-off-by: Kenfe-Mickael Laventure <mickael.laventure@gmail.com>
This commit is contained in:
Kenfe-Mickael Laventure
2017-04-10 10:01:14 -07:00
parent 15eddd0ce2
commit 22a051c88e
8 changed files with 532 additions and 493 deletions

View File

@@ -7,146 +7,149 @@ import (
"sync"
"github.com/containerd/containerd"
"github.com/containerd/containerd/log"
"github.com/containerd/containerd/windows/hcs"
specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
"golang.org/x/net/context"
winsys "golang.org/x/sys/windows"
)
var (
ErrLoadedContainer = errors.New("loaded container can only be terminated")
)
type State struct {
pid uint32
status containerd.Status
}
func (s State) Pid() uint32 {
return s.pid
}
func (s State) Status() containerd.Status {
return s.status
}
type eventCallback func(id string, evType containerd.EventType, pid, exitStatus uint32)
func loadContainers(ctx context.Context, rootDir string) ([]*container, error) {
hcs, err := hcs.LoadAll(ctx, owner, rootDir)
func loadContainers(ctx context.Context, h *hcs.HCS, sendEvent eventCallback) ([]*container, error) {
hCtr, err := h.LoadContainers(ctx)
if err != nil {
return nil, err
}
containers := make([]*container, 0)
for id, h := range hcs {
for _, c := range hCtr {
containers = append(containers, &container{
id: id,
status: containerd.RunningStatus,
hcs: h,
ctr: c,
status: containerd.RunningStatus,
sendEvent: sendEvent,
})
}
return containers, nil
}
func newContainer(id, rootDir string, pid uint32, spec RuntimeSpec, io containerd.IO, sendEvent eventCallback) (*container, error) {
hcs, err := hcs.New(rootDir, owner, id, spec.OCISpec, spec.Configuration, io)
func newContainer(ctx context.Context, h *hcs.HCS, id string, spec RuntimeSpec, io containerd.IO, sendEvent eventCallback) (*container, error) {
cio, err := hcs.NewIO(io.Stdin, io.Stdout, io.Stderr, io.Terminal)
if err != nil {
return nil, err
}
hcsCtr, err := h.CreateContainer(ctx, id, spec.OCISpec, spec.Configuration, cio)
if err != nil {
return nil, err
}
sendEvent(id, containerd.CreateEvent, hcsCtr.Pid(), 0)
return &container{
runtimePid: pid,
id: id,
hcs: hcs,
status: containerd.CreatedStatus,
ecSync: make(chan struct{}),
sendEvent: sendEvent,
ctr: hcsCtr,
status: containerd.CreatedStatus,
sendEvent: sendEvent,
}, nil
}
// container implements both containerd.Container and containerd.State
type container struct {
sync.Mutex
runtimePid uint32
id string
hcs *hcs.HCS
status containerd.Status
ec uint32
ecErr error
ecSync chan struct{}
sendEvent func(id string, evType containerd.EventType, pid, exitStatus uint32)
ctr *hcs.Container
status containerd.Status
sendEvent eventCallback
}
func (c *container) Info() containerd.ContainerInfo {
return containerd.ContainerInfo{
ID: c.id,
ID: c.ctr.ID(),
Runtime: runtimeName,
}
}
func (c *container) Start(ctx context.Context) error {
if c.runtimePid == 0 {
if c.ctr.Pid() == 0 {
return ErrLoadedContainer
}
err := c.hcs.Start(ctx, false)
err := c.ctr.Start(ctx)
if err != nil {
c.hcs.Terminate(ctx)
c.sendEvent(c.id, containerd.ExitEvent, c.runtimePid, 255)
return err
}
c.setStatus(containerd.RunningStatus)
c.sendEvent(c.id, containerd.StartEvent, c.runtimePid, 0)
c.sendEvent(c.ctr.ID(), containerd.StartEvent, c.ctr.Pid(), 0)
// Wait for our process to terminate
go func() {
c.ec, c.ecErr = c.hcs.ExitCode(context.Background())
ec, err := c.ctr.ExitCode()
if err != nil {
log.G(ctx).Debug(err)
}
c.setStatus(containerd.StoppedStatus)
c.sendEvent(c.id, containerd.ExitEvent, c.runtimePid, c.ec)
close(c.ecSync)
c.sendEvent(c.ctr.ID(), containerd.ExitEvent, c.ctr.Pid(), ec)
}()
return nil
}
func (c *container) State(ctx context.Context) (containerd.State, error) {
return &State{
pid: c.runtimePid,
status: c.getStatus(),
}, nil
return c, nil
}
func (c *container) Kill(ctx context.Context, signal uint32, all bool) error {
return c.hcs.Terminate(ctx)
if winsys.Signal(signal) == winsys.SIGKILL {
return c.ctr.Kill(ctx)
}
return c.ctr.Stop(ctx)
}
func (c *container) Exec(ctx context.Context, opts containerd.ExecOpts) (containerd.Process, error) {
if c.runtimePid == 0 {
if c.ctr.Pid() == 0 {
return nil, ErrLoadedContainer
}
pio, err := hcs.NewIO(opts.IO.Stdin, opts.IO.Stdout, opts.IO.Stderr, opts.IO.Terminal)
if err != nil {
return nil, err
}
var procSpec specs.Process
if err := json.Unmarshal(opts.Spec, &procSpec); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal oci spec")
}
p, err := c.hcs.Exec(ctx, procSpec, opts.IO)
p, err := c.ctr.AddProcess(ctx, procSpec, pio)
if err != nil {
return nil, err
}
go func() {
ec, _ := p.ExitCode()
c.sendEvent(c.id, containerd.ExitEvent, p.Pid(), ec)
ec, err := p.ExitCode()
if err != nil {
log.G(ctx).Debug(err)
}
c.sendEvent(c.ctr.ID(), containerd.ExitEvent, p.Pid(), ec)
}()
return &process{p}, nil
}
func (c *container) Status() containerd.Status {
return c.getStatus()
}
func (c *container) Pid() uint32 {
return c.ctr.Pid()
}
func (c *container) setStatus(status containerd.Status) {
c.Lock()
c.status = status
@@ -158,44 +161,3 @@ func (c *container) getStatus() containerd.Status {
defer c.Unlock()
return c.status
}
func (c *container) exitCode(ctx context.Context) (uint32, error) {
if c.runtimePid == 0 {
return 255, ErrLoadedContainer
}
<-c.ecSync
return c.ec, c.ecErr
}
func (c *container) remove(ctx context.Context) error {
return c.hcs.Remove(ctx)
}
func (c *container) getRuntimePid() uint32 {
return c.runtimePid
}
type process struct {
p *hcs.Process
}
func (p *process) State(ctx context.Context) (containerd.State, error) {
return &processState{p.p}, nil
}
func (p *process) Kill(ctx context.Context, sig uint32, all bool) error {
return p.p.Kill()
}
type processState struct {
p *hcs.Process
}
func (s *processState) Status() containerd.Status {
return s.p.Status()
}
func (s *processState) Pid() uint32 {
return s.p.Pid()
}