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

@@ -8,13 +8,13 @@ import (
"os"
"path/filepath"
"sync"
"syscall"
"time"
"github.com/containerd/containerd"
"github.com/containerd/containerd/log"
"github.com/containerd/containerd/plugin"
"github.com/containerd/containerd/windows/hcs"
"github.com/containerd/containerd/windows/pid"
specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
@@ -22,20 +22,11 @@ import (
)
const (
runtimeName = "windows"
owner = "containerd"
configFilename = "config.json"
runtimeName = "windows"
owner = "containerd"
)
// Win32 error codes that are used for various workarounds
// These really should be ALL_CAPS to match golangs syscall library and standard
// Win32 error conventions, but golint insists on CamelCase.
const (
CoEClassstring = syscall.Errno(0x800401F3) // Invalid class string
ErrorNoNetwork = syscall.Errno(1222) // The network is not present or not started
ErrorBadPathname = syscall.Errno(161) // The specified path is invalid
ErrorInvalidObject = syscall.Errno(0x800710D8) // The object identifier does not represent a valid object
)
var _ = (containerd.Runtime)(&Runtime{})
func init() {
plugin.Register(runtimeName, &plugin.Registration{
@@ -52,16 +43,30 @@ func New(ic *plugin.InitContext) (interface{}, error) {
return nil, errors.Wrapf(err, "could not create state directory at %s", rootDir)
}
r := &Runtime{
pidPool: pid.NewPool(),
containers: make(map[string]*container),
events: make(chan *containerd.Event, 2048),
eventsContext: c,
eventsCancel: cancel,
rootDir: rootDir,
hcs: hcs.New(owner, rootDir),
}
sendEvent := func(id string, evType containerd.EventType, pid, exitStatus uint32) {
r.sendEvent(id, evType, pid, exitStatus)
}
// Terminate all previous container that we may have started. We don't
// support restoring containers
ctrs, err := loadContainers(ic.Context, rootDir)
ctrs, err := loadContainers(ic.Context, r.hcs, sendEvent)
if err != nil {
return nil, err
}
for _, c := range ctrs {
c.remove(ic.Context)
c.ctr.Delete(ic.Context)
r.sendEvent(c.ctr.ID(), containerd.ExitEvent, c.ctr.Pid(), 255)
}
// Try to delete the old state dir and recreate it
@@ -72,16 +77,9 @@ func New(ic *plugin.InitContext) (interface{}, error) {
if err := os.MkdirAll(stateDir, 0755); err != nil {
return nil, errors.Wrapf(err, "could not create state directory at %s", stateDir)
}
r.stateDir = stateDir
return &Runtime{
containers: make(map[string]*container),
containersPid: make(map[uint32]struct{}),
events: make(chan *containerd.Event, 2048),
eventsContext: c,
eventsCancel: cancel,
stateDir: stateDir,
rootDir: rootDir,
}, nil
return r, nil
}
type Runtime struct {
@@ -89,10 +87,11 @@ type Runtime struct {
rootDir string
stateDir string
pidPool *pid.Pool
containers map[string]*container
containersPid map[uint32]struct{}
currentPid uint32
hcs *hcs.HCS
containers map[string]*container
events chan *containerd.Event
eventsContext context.Context
@@ -113,26 +112,19 @@ func (r *Runtime) Create(ctx context.Context, id string, opts containerd.CreateO
return nil, errors.Wrap(err, "failed to unmarshal oci spec")
}
pid, err := r.getPid()
if err != nil {
return nil, err
sendEvent := func(id string, evType containerd.EventType, pid, exitStatus uint32) {
r.sendEvent(id, evType, pid, exitStatus)
}
ctr, err := newContainer(id, r.rootDir, pid, rtSpec, opts.IO, func(id string, evType containerd.EventType, pid, exitStatus uint32) {
r.sendEvent(id, evType, pid, exitStatus)
})
ctr, err := newContainer(ctx, r.hcs, id, rtSpec, opts.IO, sendEvent)
if err != nil {
r.putPid(pid)
return nil, err
}
r.Lock()
r.containers[id] = ctr
r.containersPid[pid] = struct{}{}
r.Unlock()
r.sendEvent(id, containerd.CreateEvent, pid, 0)
return ctr, nil
}
@@ -141,30 +133,32 @@ func (r *Runtime) Delete(ctx context.Context, c containerd.Container) (uint32, e
if !ok {
return 0, fmt.Errorf("container cannot be cast as *windows.container")
}
ec, err := wc.exitCode(ctx)
ec, err := wc.ctr.ExitCode()
if err != nil {
ec = 255
log.G(ctx).WithError(err).Errorf("failed to retrieve exit code for container %s", c.Info().ID)
log.G(ctx).WithError(err).Errorf("failed to retrieve exit code for container %s", wc.ctr.ID())
}
if err = wc.remove(ctx); err == nil {
r.Lock()
delete(r.containers, c.Info().ID)
r.Unlock()
}
wc.ctr.Delete(ctx)
r.putPid(wc.getRuntimePid())
r.Lock()
delete(r.containers, wc.ctr.ID())
r.Unlock()
return ec, err
}
func (r *Runtime) Containers() ([]containerd.Container, error) {
func (r *Runtime) Containers(ctx context.Context) ([]containerd.Container, error) {
r.Lock()
defer r.Unlock()
list := make([]containerd.Container, len(r.containers))
for _, c := range r.containers {
list = append(list, c)
select {
case <-ctx.Done():
return nil, ctx.Err()
default:
list = append(list, c)
}
}
r.Unlock()
return list, nil
}
@@ -183,29 +177,3 @@ func (r *Runtime) sendEvent(id string, evType containerd.EventType, pid, exitSta
ExitStatus: exitStatus,
}
}
func (r *Runtime) getPid() (uint32, error) {
r.Lock()
defer r.Unlock()
pid := r.currentPid + 1
for pid != r.currentPid {
// 0 is reserved and invalid
if pid == 0 {
pid = 1
}
if _, ok := r.containersPid[pid]; !ok {
r.currentPid = pid
return pid, nil
}
pid++
}
return 0, errors.New("pid pool exhausted")
}
func (r *Runtime) putPid(pid uint32) {
r.Lock()
delete(r.containersPid, pid)
r.Unlock()
}