1
2
3 package main
4
5 import (
6 "context"
7 "sync"
8 "time"
9
10 "github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/options"
11 "github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/stats"
12 "github.com/Microsoft/hcsshim/internal/cmd"
13 "github.com/Microsoft/hcsshim/internal/log"
14 "github.com/Microsoft/hcsshim/internal/oc"
15 "github.com/Microsoft/hcsshim/internal/shimdiag"
16 "github.com/Microsoft/hcsshim/internal/uvm"
17 eventstypes "github.com/containerd/containerd/api/events"
18 "github.com/containerd/containerd/errdefs"
19 "github.com/containerd/containerd/runtime"
20 "github.com/containerd/containerd/runtime/v2/task"
21 "github.com/containerd/typeurl"
22 "github.com/opencontainers/runtime-spec/specs-go"
23 "github.com/pkg/errors"
24 "go.opencensus.io/trace"
25 )
26
27
28
29
30
31
32
33
34
35 func newWcowPodSandboxTask(ctx context.Context, events publisher, id, bundle string, parent *uvm.UtilityVM, nsid string) shimTask {
36 log.G(ctx).WithField("tid", id).Debug("newWcowPodSandboxTask")
37
38 wpst := &wcowPodSandboxTask{
39 events: events,
40 id: id,
41 init: newWcowPodSandboxExec(ctx, events, id, bundle),
42 host: parent,
43 closed: make(chan struct{}),
44 nsid: nsid,
45 }
46 if parent != nil {
47
48
49
50 go wpst.waitParentExit()
51 }
52
53
54 go wpst.waitInitExit()
55 return wpst
56 }
57
58 var _ = (shimTask)(&wcowPodSandboxTask{})
59
60
61
62
63
64
65
66
67
68
69 type wcowPodSandboxTask struct {
70 events publisher
71
72
73
74 id string
75
76
77
78
79
80
81
82 init *wcowPodSandboxExec
83
84
85 host *uvm.UtilityVM
86
87
88
89
90
91 nsid string
92
93 closed chan struct{}
94 closeOnce sync.Once
95 }
96
97 func (wpst *wcowPodSandboxTask) ID() string {
98 return wpst.id
99 }
100
101 func (wpst *wcowPodSandboxTask) CreateExec(ctx context.Context, req *task.ExecProcessRequest, s *specs.Process) error {
102 return errors.Wrap(errdefs.ErrNotImplemented, "WCOW Pod task should never issue exec")
103 }
104
105 func (wpst *wcowPodSandboxTask) GetExec(eid string) (shimExec, error) {
106 if eid == "" {
107 return wpst.init, nil
108 }
109
110 return nil, errors.Wrapf(errdefs.ErrNotFound, "exec: '%s' in task: '%s' not found", eid, wpst.id)
111 }
112
113 func (wpst *wcowPodSandboxTask) ListExecs() ([]shimExec, error) {
114 return []shimExec{wpst.init}, nil
115 }
116
117 func (wpst *wcowPodSandboxTask) KillExec(ctx context.Context, eid string, signal uint32, all bool) error {
118 e, err := wpst.GetExec(eid)
119 if err != nil {
120 return err
121 }
122 if all && eid != "" {
123 return errors.Wrapf(errdefs.ErrFailedPrecondition, "cannot signal all for non-empty exec: '%s'", eid)
124 }
125 err = e.Kill(ctx, signal)
126 if err != nil {
127 return err
128 }
129 return nil
130 }
131
132 func (wpst *wcowPodSandboxTask) DeleteExec(ctx context.Context, eid string) (int, uint32, time.Time, error) {
133 e, err := wpst.GetExec(eid)
134 if err != nil {
135 return 0, 0, time.Time{}, err
136 }
137 switch state := e.State(); state {
138 case shimExecStateCreated:
139 e.ForceExit(ctx, 0)
140 case shimExecStateRunning:
141 return 0, 0, time.Time{}, newExecInvalidStateError(wpst.id, eid, state, "delete")
142 }
143 status := e.Status()
144
145
146 if err := wpst.events.publishEvent(
147 ctx,
148 runtime.TaskDeleteEventTopic,
149 &eventstypes.TaskDelete{
150 ContainerID: wpst.id,
151 ID: eid,
152 Pid: status.Pid,
153 ExitStatus: status.ExitStatus,
154 ExitedAt: status.ExitedAt,
155 }); err != nil {
156 return 0, 0, time.Time{}, err
157 }
158
159 return int(status.Pid), status.ExitStatus, status.ExitedAt, nil
160 }
161
162 func (wpst *wcowPodSandboxTask) Pids(ctx context.Context) ([]options.ProcessDetails, error) {
163 return []options.ProcessDetails{
164 {
165 ProcessID: uint32(wpst.init.Pid()),
166 ExecID: wpst.init.ID(),
167 },
168 }, nil
169 }
170
171 func (wpst *wcowPodSandboxTask) Wait() *task.StateResponse {
172 <-wpst.closed
173 return wpst.init.Wait()
174 }
175
176
177
178
179
180
181
182 func (wpst *wcowPodSandboxTask) close(ctx context.Context) {
183 wpst.closeOnce.Do(func() {
184 log.G(ctx).Debug("wcowPodSandboxTask::closeOnce")
185
186 if wpst.host != nil {
187 if err := wpst.host.TearDownNetworking(ctx, wpst.nsid); err != nil {
188 log.G(ctx).WithError(err).Error("failed to cleanup networking for utility VM")
189 }
190
191 if err := wpst.host.Close(); err != nil {
192 log.G(ctx).WithError(err).Error("failed host vm shutdown")
193 }
194 }
195
196 exit := wpst.init.Status()
197
198 if err := wpst.events.publishEvent(
199 ctx,
200 runtime.TaskExitEventTopic,
201 &eventstypes.TaskExit{
202 ContainerID: wpst.id,
203 ID: exit.ID,
204 Pid: uint32(exit.Pid),
205 ExitStatus: exit.ExitStatus,
206 ExitedAt: exit.ExitedAt,
207 }); err != nil {
208 log.G(ctx).WithError(err).Error("failed to publish TaskExitEventTopic")
209 }
210 close(wpst.closed)
211 })
212 }
213
214 func (wpst *wcowPodSandboxTask) waitInitExit() {
215 ctx, span := oc.StartSpan(context.Background(), "wcowPodSandboxTask::waitInitExit")
216 defer span.End()
217 span.AddAttributes(trace.StringAttribute("tid", wpst.id))
218
219
220 wpst.init.Wait()
221
222
223 wpst.close(ctx)
224 }
225
226 func (wpst *wcowPodSandboxTask) waitParentExit() {
227 ctx, span := oc.StartSpan(context.Background(), "wcowPodSandboxTask::waitParentExit")
228 defer span.End()
229 span.AddAttributes(trace.StringAttribute("tid", wpst.id))
230
231 werr := wpst.host.Wait()
232 if werr != nil {
233 log.G(ctx).WithError(werr).Error("parent wait failed")
234 }
235
236
237
238 wpst.init.ForceExit(ctx, 1)
239
240
241 wpst.close(ctx)
242 }
243
244 func (wpst *wcowPodSandboxTask) ExecInHost(ctx context.Context, req *shimdiag.ExecProcessRequest) (int, error) {
245 cmdReq := &cmd.CmdProcessRequest{
246 Args: req.Args,
247 Workdir: req.Workdir,
248 Terminal: req.Terminal,
249 Stdin: req.Stdin,
250 Stdout: req.Stdout,
251 Stderr: req.Stderr,
252 }
253 if wpst.host == nil {
254 return 0, errTaskNotIsolated
255 }
256 return cmd.ExecInUvm(ctx, wpst.host, cmdReq)
257 }
258
259 func (wpst *wcowPodSandboxTask) DumpGuestStacks(ctx context.Context) string {
260 if wpst.host != nil {
261 stacks, err := wpst.host.DumpStacks(ctx)
262 if err != nil {
263 log.G(ctx).WithError(err).Warn("failed to capture guest stacks")
264 } else {
265 return stacks
266 }
267 }
268 return ""
269 }
270
271 func (wpst *wcowPodSandboxTask) Update(ctx context.Context, req *task.UpdateTaskRequest) error {
272 if wpst.host == nil {
273 return errTaskNotIsolated
274 }
275
276 resources, err := typeurl.UnmarshalAny(req.Resources)
277 if err != nil {
278 return errors.Wrapf(err, "failed to unmarshal resources for container %s update request", req.ID)
279 }
280
281 if err := verifyTaskUpdateResourcesType(resources); err != nil {
282 return err
283 }
284
285 return wpst.host.Update(ctx, resources, req.Annotations)
286 }
287
288 func (wpst *wcowPodSandboxTask) Share(ctx context.Context, req *shimdiag.ShareRequest) error {
289 if wpst.host == nil {
290 return errTaskNotIsolated
291 }
292 return wpst.host.Share(ctx, req.HostPath, req.UvmPath, req.ReadOnly)
293 }
294
295 func (wpst *wcowPodSandboxTask) Stats(ctx context.Context) (*stats.Statistics, error) {
296 stats := &stats.Statistics{}
297 if wpst.host == nil {
298 return stats, nil
299 }
300 vmStats, err := wpst.host.Stats(ctx)
301 if err != nil && !isStatsNotFound(err) {
302 return nil, err
303 }
304 stats.VM = vmStats
305 return stats, nil
306 }
307
308 func (wpst *wcowPodSandboxTask) ProcessorInfo(ctx context.Context) (*processorInfo, error) {
309 if wpst.host == nil {
310 return nil, errTaskNotIsolated
311 }
312 return &processorInfo{
313 count: wpst.host.ProcessorCount(),
314 }, nil
315 }
316
View as plain text