Skip to content

Commit 5c8e0ef

Browse files
committed
windows: Add servicing code
Signed-off-by: Kenfe-Mickael Laventure <mickael.laventure@gmail.com>
1 parent 4bb9ac2 commit 5c8e0ef

File tree

2 files changed

+98
-44
lines changed

2 files changed

+98
-44
lines changed

windows/runtime.go

Lines changed: 92 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"time"
1111

1212
"github.com/Microsoft/hcsshim"
13+
"github.com/Sirupsen/logrus"
1314
"github.com/boltdb/bolt"
1415
eventsapi "github.com/containerd/containerd/api/services/events/v1"
1516
containerdtypes "github.com/containerd/containerd/api/types"
@@ -122,27 +123,7 @@ func (r *windowsRuntime) Create(ctx context.Context, id string, opts runtime.Cre
122123
createOpts.TerminateDuration = defaultTerminateDuration
123124
}
124125

125-
t, err := r.newTask(ctx, r.emitter, namespace, id, spec, opts.IO, createOpts)
126-
if err != nil {
127-
return nil, err
128-
}
129-
130-
r.tasks.Add(ctx, t)
131-
132-
r.emitter.Post(events.WithTopic(ctx, "/tasks/create"), &eventsapi.TaskCreate{
133-
ContainerID: id,
134-
IO: &eventsapi.TaskIO{
135-
Stdin: opts.IO.Stdin,
136-
Stdout: opts.IO.Stdout,
137-
Stderr: opts.IO.Stderr,
138-
Terminal: opts.IO.Terminal,
139-
},
140-
Pid: t.pid,
141-
Rootfs: t.rootfs,
142-
// TODO: what should be in Bundle for windows?
143-
})
144-
145-
return t, nil
126+
return r.newTask(ctx, namespace, id, spec, opts.IO, createOpts)
146127
}
147128

148129
func (r *windowsRuntime) Get(ctx context.Context, id string) (runtime.Task, error) {
@@ -161,12 +142,29 @@ func (r *windowsRuntime) Delete(ctx context.Context, t runtime.Task) (*runtime.E
161142

162143
// TODO(mlaventure): stop monitor on this task
163144

164-
state, _ := wt.State(ctx)
145+
var (
146+
err error
147+
needServicing bool
148+
state, _ = wt.State(ctx)
149+
)
165150
switch state.Status {
166-
case runtime.StoppedStatus, runtime.CreatedStatus:
151+
case runtime.StoppedStatus:
152+
// Only try to service a container if it was started and it's not a
153+
// servicing task itself
154+
if wt.servicing == false {
155+
needServicing, err = wt.hcsContainer.HasPendingUpdates()
156+
if err != nil {
157+
needServicing = false
158+
log.G(ctx).WithError(err).
159+
WithFields(logrus.Fields{"id": wt.id, "pid": wt.pid}).
160+
Error("failed to check if container needs servicing")
161+
}
162+
}
163+
fallthrough
164+
case runtime.CreatedStatus:
167165
// if it's stopped or in created state, we need to shutdown the
168166
// container before removing it
169-
if err := wt.stop(ctx); err != nil {
167+
if err = wt.stop(ctx); err != nil {
170168
return nil, err
171169
}
172170
default:
@@ -203,11 +201,18 @@ func (r *windowsRuntime) Delete(ctx context.Context, t runtime.Task) (*runtime.E
203201
ExitedAt: rtExit.Timestamp,
204202
})
205203

204+
if needServicing {
205+
ns, _ := namespaces.Namespace(ctx)
206+
serviceCtx := log.WithLogger(context.Background(), log.GetLogger(ctx))
207+
serviceCtx = namespaces.WithNamespace(serviceCtx, ns)
208+
r.serviceTask(serviceCtx, ns, wt.id+"_servicing", wt.spec)
209+
}
210+
206211
// We were never started, return failure
207212
return rtExit, nil
208213
}
209214

210-
func (r *windowsRuntime) newTask(ctx context.Context, emitter *events.Emitter, namespace, id string, spec *specs.Spec, io runtime.IO, createOpts *hcsshimopts.CreateOptions) (*task, error) {
215+
func (r *windowsRuntime) newTask(ctx context.Context, namespace, id string, spec *specs.Spec, io runtime.IO, createOpts *hcsshimopts.CreateOptions) (*task, error) {
211216
var (
212217
err error
213218
pset *pipeSet
@@ -281,29 +286,45 @@ func (r *windowsRuntime) newTask(ctx context.Context, emitter *events.Emitter, n
281286
return nil, errors.Wrap(err, "hcsshim failed to spawn task")
282287
}
283288

284-
var rootfs []*containerdtypes.Mount
285-
for _, l := range append([]string{conf.LayerFolderPath}, spec.Windows.LayerFolders...) {
286-
rootfs = append(rootfs, &containerdtypes.Mount{
287-
Type: "windows-layer",
288-
Source: l,
289-
})
290-
}
291-
292-
return &task{
289+
t := &task{
293290
id: id,
294291
namespace: namespace,
295292
pid: pid,
296293
io: pset,
297294
status: runtime.CreatedStatus,
298-
initSpec: spec.Process,
295+
spec: spec,
299296
processes: make(map[string]*process),
300297
hyperV: spec.Windows.HyperV != nil,
301-
rootfs: rootfs,
302-
emitter: emitter,
298+
emitter: r.emitter,
299+
rwLayer: conf.LayerFolderPath,
303300
pidPool: r.pidPool,
304301
hcsContainer: ctr,
305302
terminateDuration: createOpts.TerminateDuration,
306-
}, nil
303+
}
304+
r.tasks.Add(ctx, t)
305+
306+
var rootfs []*containerdtypes.Mount
307+
for _, l := range append([]string{t.rwLayer}, spec.Windows.LayerFolders...) {
308+
rootfs = append(rootfs, &containerdtypes.Mount{
309+
Type: "windows-layer",
310+
Source: l,
311+
})
312+
}
313+
314+
r.emitter.Post(events.WithTopic(ctx, "/tasks/create"), &eventsapi.TaskCreate{
315+
ContainerID: id,
316+
IO: &eventsapi.TaskIO{
317+
Stdin: io.Stdin,
318+
Stdout: io.Stdout,
319+
Stderr: io.Stderr,
320+
Terminal: io.Terminal,
321+
},
322+
Pid: t.pid,
323+
Rootfs: rootfs,
324+
// TODO: what should be in Bundle for windows?
325+
})
326+
327+
return t, nil
307328
}
308329

309330
func (r *windowsRuntime) cleanup(ctx context.Context) {
@@ -354,3 +375,36 @@ func (r *windowsRuntime) cleanup(ctx context.Context) {
354375

355376
}
356377
}
378+
379+
func (r *windowsRuntime) serviceTask(ctx context.Context, namespace, id string, spec *specs.Spec) {
380+
var (
381+
err error
382+
t *task
383+
io runtime.IO
384+
createOpts = &hcsshimopts.CreateOptions{
385+
TerminateDuration: defaultTerminateDuration,
386+
}
387+
)
388+
389+
t, err = r.newTask(ctx, namespace, id, spec, io, createOpts)
390+
if err != nil {
391+
log.G(ctx).WithError(err).WithField("id", id).
392+
Warn("failed to created servicing task")
393+
return
394+
}
395+
t.servicing = true
396+
397+
err = t.Start(ctx)
398+
switch err {
399+
case nil:
400+
<-t.getProcess(id).exitCh
401+
default:
402+
log.G(ctx).WithError(err).WithField("id", id).
403+
Warn("failed to start servicing task")
404+
}
405+
406+
if _, err = r.Delete(ctx, t); err != nil {
407+
log.G(ctx).WithError(err).WithField("id", id).
408+
Warn("failed to stop servicing task")
409+
}
410+
}

windows/task.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212
"github.com/Microsoft/hcsshim"
1313
"github.com/Sirupsen/logrus"
1414
eventsapi "github.com/containerd/containerd/api/services/events/v1"
15-
containerdtypes "github.com/containerd/containerd/api/types"
1615
"github.com/containerd/containerd/errdefs"
1716
"github.com/containerd/containerd/events"
1817
"github.com/containerd/containerd/log"
@@ -31,16 +30,17 @@ type task struct {
3130
pid uint32
3231
io *pipeSet
3332
status runtime.Status
34-
initSpec *specs.Process
33+
spec *specs.Spec
3534
processes map[string]*process
3635
hyperV bool
3736

38-
rootfs []*containerdtypes.Mount
3937
emitter *events.Emitter
38+
rwLayer string
4039

4140
pidPool *pidPool
4241
hcsContainer hcsshim.Container
4342
terminateDuration time.Duration
43+
servicing bool
4444
}
4545

4646
func (t *task) ID() string {
@@ -107,7 +107,7 @@ func (t *task) Info() runtime.TaskInfo {
107107
}
108108

109109
func (t *task) Start(ctx context.Context) error {
110-
conf := newProcessConfig(t.initSpec, t.io)
110+
conf := newProcessConfig(t.spec.Process, t.io)
111111
if _, err := t.newProcess(ctx, t.id, conf, t.io); err != nil {
112112
return err
113113
}
@@ -173,7 +173,7 @@ func (t *task) Exec(ctx context.Context, id string, opts runtime.ExecOpts) (runt
173173
}
174174
spec := s.(*specs.Process)
175175
if spec.Cwd == "" {
176-
spec.Cwd = t.initSpec.Cwd
176+
spec.Cwd = t.spec.Process.Cwd
177177
}
178178

179179
var pset *pipeSet
@@ -431,6 +431,6 @@ func (t *task) cleanup() {
431431
for _, p := range t.processes {
432432
t.removeProcessNL(p.id)
433433
}
434-
removeLayer(context.Background(), t.rootfs[len(t.rootfs)-1].Source)
434+
removeLayer(context.Background(), t.rwLayer)
435435
t.Unlock()
436436
}

0 commit comments

Comments
 (0)