windows process exit timestamp

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
Michael Crosby 2017-04-13 15:30:42 -07:00
parent efe177ed77
commit 5d3bc1a4a7
5 changed files with 33 additions and 27 deletions

View File

@ -52,5 +52,4 @@ message Event {
uint32 pid = 3; uint32 pid = 3;
uint32 exit_status = 4; uint32 exit_status = 4;
google.protobuf.Timestamp exited_at = 5 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; google.protobuf.Timestamp exited_at = 5 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
} }

View File

@ -5,6 +5,7 @@ package windows
import ( import (
"encoding/json" "encoding/json"
"sync" "sync"
"time"
"github.com/containerd/containerd" "github.com/containerd/containerd"
"github.com/containerd/containerd/log" "github.com/containerd/containerd/log"
@ -19,7 +20,7 @@ var (
ErrLoadedContainer = errors.New("loaded container can only be terminated") ErrLoadedContainer = errors.New("loaded container can only be terminated")
) )
type eventCallback func(id string, evType containerd.EventType, pid, exitStatus uint32) type eventCallback func(id string, evType containerd.EventType, pid, exitStatus uint32, exitedAt time.Time)
func loadContainers(ctx context.Context, h *hcs.HCS, sendEvent eventCallback) ([]*container, error) { func loadContainers(ctx context.Context, h *hcs.HCS, sendEvent eventCallback) ([]*container, error) {
hCtr, err := h.LoadContainers(ctx) hCtr, err := h.LoadContainers(ctx)
@ -49,7 +50,7 @@ func newContainer(ctx context.Context, h *hcs.HCS, id string, spec RuntimeSpec,
if err != nil { if err != nil {
return nil, err return nil, err
} }
sendEvent(id, containerd.CreateEvent, hcsCtr.Pid(), 0) sendEvent(id, containerd.CreateEvent, hcsCtr.Pid(), 0, time.Time{})
return &container{ return &container{
ctr: hcsCtr, ctr: hcsCtr,
@ -85,7 +86,7 @@ func (c *container) Start(ctx context.Context) error {
} }
c.setStatus(containerd.RunningStatus) c.setStatus(containerd.RunningStatus)
c.sendEvent(c.ctr.ID(), containerd.StartEvent, c.ctr.Pid(), 0) c.sendEvent(c.ctr.ID(), containerd.StartEvent, c.ctr.Pid(), 0, time.Time{})
// Wait for our process to terminate // Wait for our process to terminate
go func() { go func() {
@ -94,7 +95,7 @@ func (c *container) Start(ctx context.Context) error {
log.G(ctx).Debug(err) log.G(ctx).Debug(err)
} }
c.setStatus(containerd.StoppedStatus) c.setStatus(containerd.StoppedStatus)
c.sendEvent(c.ctr.ID(), containerd.ExitEvent, c.ctr.Pid(), ec) c.sendEvent(c.ctr.ID(), containerd.ExitEvent, c.ctr.Pid(), ec, c.ctr.Processes()[0].ExitedAt())
}() }()
return nil return nil
@ -136,7 +137,7 @@ func (c *container) Exec(ctx context.Context, opts containerd.ExecOpts) (contain
if err != nil { if err != nil {
log.G(ctx).Debug(err) log.G(ctx).Debug(err)
} }
c.sendEvent(c.ctr.ID(), containerd.ExitEvent, p.Pid(), ec) c.sendEvent(c.ctr.ID(), containerd.ExitEvent, p.Pid(), ec, p.ExitedAt())
}() }()
return &process{p}, nil return &process{p}, nil

View File

@ -167,6 +167,10 @@ func (c *Container) Pid() uint32 {
return c.pid return c.pid
} }
func (c *Container) Processes() []*Process {
return c.processes
}
func (c *Container) Start(ctx context.Context) error { func (c *Container) Start(ctx context.Context) error {
_, err := c.addProcess(ctx, c.spec.Process, c.io) _, err := c.addProcess(ctx, c.spec.Process, c.io)
return err return err

View File

@ -4,6 +4,7 @@ package hcs
import ( import (
"syscall" "syscall"
"time"
"github.com/Microsoft/hcsshim" "github.com/Microsoft/hcsshim"
"github.com/containerd/containerd" "github.com/containerd/containerd"
@ -13,11 +14,12 @@ import (
type Process struct { type Process struct {
hcsshim.Process hcsshim.Process
pid uint32 pid uint32
io *IO io *IO
ec uint32 ec uint32
ecErr error exitedAt time.Time
ecSync chan struct{} ecErr error
ecSync chan struct{}
} }
func (p *Process) Pid() uint32 { func (p *Process) Pid() uint32 {
@ -29,6 +31,10 @@ func (p *Process) ExitCode() (uint32, error) {
return p.ec, p.ecErr return p.ec, p.ecErr
} }
func (p *Process) ExitedAt() time.Time {
return p.exitedAt
}
func (p *Process) Status() containerd.Status { func (p *Process) Status() containerd.Status {
select { select {
case <-p.ecSync: case <-p.ecSync:
@ -60,6 +66,6 @@ func processExitCode(containerID string, p *Process) (uint32, error) {
// Well, unknown exit code it is // Well, unknown exit code it is
ec = 255 ec = 255
} }
p.exitedAt = time.Now()
return uint32(ec), err return uint32(ec), err
} }

View File

@ -53,20 +53,16 @@ func New(ic *plugin.InitContext) (interface{}, error) {
hcs: hcs.New(owner, 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 // Terminate all previous container that we may have started. We don't
// support restoring containers // support restoring containers
ctrs, err := loadContainers(ic.Context, r.hcs, sendEvent) ctrs, err := loadContainers(ic.Context, r.hcs, r.sendEvent)
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, c := range ctrs { for _, c := range ctrs {
c.ctr.Delete(ic.Context) c.ctr.Delete(ic.Context)
r.sendEvent(c.ctr.ID(), containerd.ExitEvent, c.ctr.Pid(), 255) r.sendEvent(c.ctr.ID(), containerd.ExitEvent, c.ctr.Pid(), 255, time.Time{})
} }
// Try to delete the old state dir and recreate it // Try to delete the old state dir and recreate it
@ -112,11 +108,7 @@ func (r *Runtime) Create(ctx context.Context, id string, opts containerd.CreateO
return nil, errors.Wrap(err, "failed to unmarshal oci spec") return nil, errors.Wrap(err, "failed to unmarshal oci spec")
} }
sendEvent := func(id string, evType containerd.EventType, pid, exitStatus uint32) { ctr, err := newContainer(ctx, r.hcs, id, rtSpec, opts.IO, r.sendEvent)
r.sendEvent(id, evType, pid, exitStatus)
}
ctr, err := newContainer(ctx, r.hcs, id, rtSpec, opts.IO, sendEvent)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -128,10 +120,10 @@ func (r *Runtime) Create(ctx context.Context, id string, opts containerd.CreateO
return ctr, nil return ctr, nil
} }
func (r *Runtime) Delete(ctx context.Context, c containerd.Container) (uint32, error) { func (r *Runtime) Delete(ctx context.Context, c containerd.Container) (*containerd.Exit, error) {
wc, ok := c.(*container) wc, ok := c.(*container)
if !ok { if !ok {
return 0, fmt.Errorf("container cannot be cast as *windows.container") return nil, fmt.Errorf("container cannot be cast as *windows.container")
} }
ec, err := wc.ctr.ExitCode() ec, err := wc.ctr.ExitCode()
if err != nil { if err != nil {
@ -144,7 +136,10 @@ func (r *Runtime) Delete(ctx context.Context, c containerd.Container) (uint32, e
delete(r.containers, wc.ctr.ID()) delete(r.containers, wc.ctr.ID())
r.Unlock() r.Unlock()
return ec, err return &containerd.Exit{
Status: ec,
Timestamp: wc.ctr.Processes()[0].ExitedAt(),
}, nil
} }
func (r *Runtime) Containers(ctx context.Context) ([]containerd.Container, error) { func (r *Runtime) Containers(ctx context.Context) ([]containerd.Container, error) {
@ -167,7 +162,7 @@ func (r *Runtime) Events(ctx context.Context) <-chan *containerd.Event {
return r.events return r.events
} }
func (r *Runtime) sendEvent(id string, evType containerd.EventType, pid, exitStatus uint32) { func (r *Runtime) sendEvent(id string, evType containerd.EventType, pid, exitStatus uint32, exitedAt time.Time) {
r.events <- &containerd.Event{ r.events <- &containerd.Event{
Timestamp: time.Now(), Timestamp: time.Now(),
Runtime: runtimeName, Runtime: runtimeName,
@ -175,5 +170,6 @@ func (r *Runtime) sendEvent(id string, evType containerd.EventType, pid, exitSta
Pid: pid, Pid: pid,
ID: id, ID: id,
ExitStatus: exitStatus, ExitStatus: exitStatus,
ExitedAt: exitedAt,
} }
} }