github.com/sams1990/dockerrepo@v17.12.1-ce-rc2+incompatible/libcontainerd/client_daemon.go (about) 1 // +build !windows 2 3 package libcontainerd 4 5 import ( 6 "context" 7 "encoding/json" 8 "fmt" 9 "io" 10 "os" 11 "path/filepath" 12 "reflect" 13 "runtime" 14 "strings" 15 "sync" 16 "syscall" 17 "time" 18 19 "google.golang.org/grpc" 20 "google.golang.org/grpc/codes" 21 "google.golang.org/grpc/status" 22 23 "github.com/containerd/containerd" 24 "github.com/containerd/containerd/api/events" 25 eventsapi "github.com/containerd/containerd/api/services/events/v1" 26 "github.com/containerd/containerd/api/types" 27 "github.com/containerd/containerd/archive" 28 "github.com/containerd/containerd/cio" 29 "github.com/containerd/containerd/content" 30 "github.com/containerd/containerd/errdefs" 31 "github.com/containerd/containerd/images" 32 "github.com/containerd/containerd/linux/runctypes" 33 "github.com/containerd/typeurl" 34 "github.com/docker/docker/pkg/ioutils" 35 "github.com/opencontainers/image-spec/specs-go/v1" 36 specs "github.com/opencontainers/runtime-spec/specs-go" 37 "github.com/pkg/errors" 38 "github.com/sirupsen/logrus" 39 ) 40 41 // InitProcessName is the name given to the first process of a 42 // container 43 const InitProcessName = "init" 44 45 type container struct { 46 mu sync.Mutex 47 48 bundleDir string 49 ctr containerd.Container 50 task containerd.Task 51 execs map[string]containerd.Process 52 oomKilled bool 53 } 54 55 func (c *container) setTask(t containerd.Task) { 56 c.mu.Lock() 57 c.task = t 58 c.mu.Unlock() 59 } 60 61 func (c *container) getTask() containerd.Task { 62 c.mu.Lock() 63 t := c.task 64 c.mu.Unlock() 65 return t 66 } 67 68 func (c *container) addProcess(id string, p containerd.Process) { 69 c.mu.Lock() 70 if c.execs == nil { 71 c.execs = make(map[string]containerd.Process) 72 } 73 c.execs[id] = p 74 c.mu.Unlock() 75 } 76 77 func (c *container) deleteProcess(id string) { 78 c.mu.Lock() 79 delete(c.execs, id) 80 c.mu.Unlock() 81 } 82 83 func (c *container) getProcess(id string) containerd.Process { 84 c.mu.Lock() 85 p := c.execs[id] 86 c.mu.Unlock() 87 return p 88 } 89 90 func (c *container) setOOMKilled(killed bool) { 91 c.mu.Lock() 92 c.oomKilled = killed 93 c.mu.Unlock() 94 } 95 96 func (c *container) getOOMKilled() bool { 97 c.mu.Lock() 98 killed := c.oomKilled 99 c.mu.Unlock() 100 return killed 101 } 102 103 type client struct { 104 sync.RWMutex // protects containers map 105 106 remote *containerd.Client 107 stateDir string 108 logger *logrus.Entry 109 110 namespace string 111 backend Backend 112 eventQ queue 113 containers map[string]*container 114 } 115 116 func (c *client) setRemote(remote *containerd.Client) { 117 c.Lock() 118 c.remote = remote 119 c.Unlock() 120 } 121 122 func (c *client) getRemote() *containerd.Client { 123 c.RLock() 124 remote := c.remote 125 c.RUnlock() 126 return remote 127 } 128 129 func (c *client) Version(ctx context.Context) (containerd.Version, error) { 130 return c.getRemote().Version(ctx) 131 } 132 133 func (c *client) Restore(ctx context.Context, id string, attachStdio StdioCallback) (alive bool, pid int, err error) { 134 c.Lock() 135 defer c.Unlock() 136 137 var rio cio.IO 138 defer func() { 139 err = wrapError(err) 140 }() 141 142 ctr, err := c.remote.LoadContainer(ctx, id) 143 if err != nil { 144 return false, -1, errors.WithStack(err) 145 } 146 147 defer func() { 148 if err != nil && rio != nil { 149 rio.Cancel() 150 rio.Close() 151 } 152 }() 153 154 t, err := ctr.Task(ctx, func(fifos *cio.FIFOSet) (cio.IO, error) { 155 io, err := newIOPipe(fifos) 156 if err != nil { 157 return nil, err 158 } 159 160 rio, err = attachStdio(io) 161 return rio, err 162 }) 163 if err != nil && !strings.Contains(err.Error(), "no running task found") { 164 return false, -1, err 165 } 166 167 if t != nil { 168 s, err := t.Status(ctx) 169 if err != nil { 170 return false, -1, err 171 } 172 173 alive = s.Status != containerd.Stopped 174 pid = int(t.Pid()) 175 } 176 c.containers[id] = &container{ 177 bundleDir: filepath.Join(c.stateDir, id), 178 ctr: ctr, 179 task: t, 180 // TODO(mlaventure): load execs 181 } 182 183 c.logger.WithFields(logrus.Fields{ 184 "container": id, 185 "alive": alive, 186 "pid": pid, 187 }).Debug("restored container") 188 189 return alive, pid, nil 190 } 191 192 func (c *client) Create(ctx context.Context, id string, ociSpec *specs.Spec, runtimeOptions interface{}) error { 193 if ctr := c.getContainer(id); ctr != nil { 194 return errors.WithStack(newConflictError("id already in use")) 195 } 196 197 bdir, err := prepareBundleDir(filepath.Join(c.stateDir, id), ociSpec) 198 if err != nil { 199 return wrapSystemError(errors.Wrap(err, "prepare bundle dir failed")) 200 } 201 202 c.logger.WithField("bundle", bdir).WithField("root", ociSpec.Root.Path).Debug("bundle dir created") 203 204 cdCtr, err := c.getRemote().NewContainer(ctx, id, 205 containerd.WithSpec(ociSpec), 206 // TODO(mlaventure): when containerd support lcow, revisit runtime value 207 containerd.WithRuntime(fmt.Sprintf("io.containerd.runtime.v1.%s", runtime.GOOS), runtimeOptions)) 208 if err != nil { 209 return err 210 } 211 212 c.Lock() 213 c.containers[id] = &container{ 214 bundleDir: bdir, 215 ctr: cdCtr, 216 } 217 c.Unlock() 218 219 return nil 220 } 221 222 // Start create and start a task for the specified containerd id 223 func (c *client) Start(ctx context.Context, id, checkpointDir string, withStdin bool, attachStdio StdioCallback) (int, error) { 224 ctr := c.getContainer(id) 225 if ctr == nil { 226 return -1, errors.WithStack(newNotFoundError("no such container")) 227 } 228 if t := ctr.getTask(); t != nil { 229 return -1, errors.WithStack(newConflictError("container already started")) 230 } 231 232 var ( 233 cp *types.Descriptor 234 t containerd.Task 235 rio cio.IO 236 err error 237 stdinCloseSync = make(chan struct{}) 238 ) 239 240 if checkpointDir != "" { 241 // write checkpoint to the content store 242 tar := archive.Diff(ctx, "", checkpointDir) 243 cp, err = c.writeContent(ctx, images.MediaTypeContainerd1Checkpoint, checkpointDir, tar) 244 // remove the checkpoint when we're done 245 defer func() { 246 if cp != nil { 247 err := c.getRemote().ContentStore().Delete(context.Background(), cp.Digest) 248 if err != nil { 249 c.logger.WithError(err).WithFields(logrus.Fields{ 250 "ref": checkpointDir, 251 "digest": cp.Digest, 252 }).Warnf("failed to delete temporary checkpoint entry") 253 } 254 } 255 }() 256 if err := tar.Close(); err != nil { 257 return -1, errors.Wrap(err, "failed to close checkpoint tar stream") 258 } 259 if err != nil { 260 return -1, errors.Wrapf(err, "failed to upload checkpoint to containerd") 261 } 262 } 263 264 spec, err := ctr.ctr.Spec(ctx) 265 if err != nil { 266 return -1, errors.Wrap(err, "failed to retrieve spec") 267 } 268 uid, gid := getSpecUser(spec) 269 t, err = ctr.ctr.NewTask(ctx, 270 func(id string) (cio.IO, error) { 271 fifos := newFIFOSet(ctr.bundleDir, id, InitProcessName, withStdin, spec.Process.Terminal) 272 rio, err = c.createIO(fifos, id, InitProcessName, stdinCloseSync, attachStdio) 273 return rio, err 274 }, 275 func(_ context.Context, _ *containerd.Client, info *containerd.TaskInfo) error { 276 info.Checkpoint = cp 277 info.Options = &runctypes.CreateOptions{ 278 IoUid: uint32(uid), 279 IoGid: uint32(gid), 280 NoPivotRoot: os.Getenv("DOCKER_RAMDISK") != "", 281 } 282 return nil 283 }) 284 if err != nil { 285 close(stdinCloseSync) 286 if rio != nil { 287 rio.Cancel() 288 rio.Close() 289 } 290 return -1, err 291 } 292 293 ctr.setTask(t) 294 295 // Signal c.createIO that it can call CloseIO 296 close(stdinCloseSync) 297 298 if err := t.Start(ctx); err != nil { 299 if _, err := t.Delete(ctx); err != nil { 300 c.logger.WithError(err).WithField("container", id). 301 Error("failed to delete task after fail start") 302 } 303 ctr.setTask(nil) 304 return -1, err 305 } 306 307 return int(t.Pid()), nil 308 } 309 310 func (c *client) Exec(ctx context.Context, containerID, processID string, spec *specs.Process, withStdin bool, attachStdio StdioCallback) (int, error) { 311 ctr := c.getContainer(containerID) 312 if ctr == nil { 313 return -1, errors.WithStack(newNotFoundError("no such container")) 314 } 315 t := ctr.getTask() 316 if t == nil { 317 return -1, errors.WithStack(newInvalidParameterError("container is not running")) 318 } 319 320 if p := ctr.getProcess(processID); p != nil { 321 return -1, errors.WithStack(newConflictError("id already in use")) 322 } 323 324 var ( 325 p containerd.Process 326 rio cio.IO 327 err error 328 stdinCloseSync = make(chan struct{}) 329 ) 330 331 fifos := newFIFOSet(ctr.bundleDir, containerID, processID, withStdin, spec.Terminal) 332 333 defer func() { 334 if err != nil { 335 if rio != nil { 336 rio.Cancel() 337 rio.Close() 338 } 339 rmFIFOSet(fifos) 340 } 341 }() 342 343 p, err = t.Exec(ctx, processID, spec, func(id string) (cio.IO, error) { 344 rio, err = c.createIO(fifos, containerID, processID, stdinCloseSync, attachStdio) 345 return rio, err 346 }) 347 if err != nil { 348 close(stdinCloseSync) 349 if rio != nil { 350 rio.Cancel() 351 rio.Close() 352 } 353 return -1, err 354 } 355 356 ctr.addProcess(processID, p) 357 358 // Signal c.createIO that it can call CloseIO 359 close(stdinCloseSync) 360 361 if err = p.Start(ctx); err != nil { 362 p.Delete(context.Background()) 363 ctr.deleteProcess(processID) 364 return -1, err 365 } 366 367 return int(p.Pid()), nil 368 } 369 370 func (c *client) SignalProcess(ctx context.Context, containerID, processID string, signal int) error { 371 p, err := c.getProcess(containerID, processID) 372 if err != nil { 373 return err 374 } 375 return wrapError(p.Kill(ctx, syscall.Signal(signal))) 376 } 377 378 func (c *client) ResizeTerminal(ctx context.Context, containerID, processID string, width, height int) error { 379 p, err := c.getProcess(containerID, processID) 380 if err != nil { 381 return err 382 } 383 384 return p.Resize(ctx, uint32(width), uint32(height)) 385 } 386 387 func (c *client) CloseStdin(ctx context.Context, containerID, processID string) error { 388 p, err := c.getProcess(containerID, processID) 389 if err != nil { 390 return err 391 } 392 393 return p.CloseIO(ctx, containerd.WithStdinCloser) 394 } 395 396 func (c *client) Pause(ctx context.Context, containerID string) error { 397 p, err := c.getProcess(containerID, InitProcessName) 398 if err != nil { 399 return err 400 } 401 402 return p.(containerd.Task).Pause(ctx) 403 } 404 405 func (c *client) Resume(ctx context.Context, containerID string) error { 406 p, err := c.getProcess(containerID, InitProcessName) 407 if err != nil { 408 return err 409 } 410 411 return p.(containerd.Task).Resume(ctx) 412 } 413 414 func (c *client) Stats(ctx context.Context, containerID string) (*Stats, error) { 415 p, err := c.getProcess(containerID, InitProcessName) 416 if err != nil { 417 return nil, err 418 } 419 420 m, err := p.(containerd.Task).Metrics(ctx) 421 if err != nil { 422 return nil, err 423 } 424 425 v, err := typeurl.UnmarshalAny(m.Data) 426 if err != nil { 427 return nil, err 428 } 429 return interfaceToStats(m.Timestamp, v), nil 430 } 431 432 func (c *client) ListPids(ctx context.Context, containerID string) ([]uint32, error) { 433 p, err := c.getProcess(containerID, InitProcessName) 434 if err != nil { 435 return nil, err 436 } 437 438 pis, err := p.(containerd.Task).Pids(ctx) 439 if err != nil { 440 return nil, err 441 } 442 443 var pids []uint32 444 for _, i := range pis { 445 pids = append(pids, i.Pid) 446 } 447 448 return pids, nil 449 } 450 451 func (c *client) Summary(ctx context.Context, containerID string) ([]Summary, error) { 452 p, err := c.getProcess(containerID, InitProcessName) 453 if err != nil { 454 return nil, err 455 } 456 457 pis, err := p.(containerd.Task).Pids(ctx) 458 if err != nil { 459 return nil, err 460 } 461 462 var infos []Summary 463 for _, pi := range pis { 464 i, err := typeurl.UnmarshalAny(pi.Info) 465 if err != nil { 466 return nil, errors.Wrap(err, "unable to decode process details") 467 } 468 s, err := summaryFromInterface(i) 469 if err != nil { 470 return nil, err 471 } 472 infos = append(infos, *s) 473 } 474 475 return infos, nil 476 } 477 478 func (c *client) DeleteTask(ctx context.Context, containerID string) (uint32, time.Time, error) { 479 p, err := c.getProcess(containerID, InitProcessName) 480 if err != nil { 481 return 255, time.Now(), nil 482 } 483 484 status, err := p.(containerd.Task).Delete(ctx) 485 if err != nil { 486 return 255, time.Now(), nil 487 } 488 489 if ctr := c.getContainer(containerID); ctr != nil { 490 ctr.setTask(nil) 491 } 492 return status.ExitCode(), status.ExitTime(), nil 493 } 494 495 func (c *client) Delete(ctx context.Context, containerID string) error { 496 ctr := c.getContainer(containerID) 497 if ctr == nil { 498 return errors.WithStack(newNotFoundError("no such container")) 499 } 500 501 if err := ctr.ctr.Delete(ctx); err != nil { 502 return err 503 } 504 505 if os.Getenv("LIBCONTAINERD_NOCLEAN") != "1" { 506 if err := os.RemoveAll(ctr.bundleDir); err != nil { 507 c.logger.WithError(err).WithFields(logrus.Fields{ 508 "container": containerID, 509 "bundle": ctr.bundleDir, 510 }).Error("failed to remove state dir") 511 } 512 } 513 514 c.removeContainer(containerID) 515 516 return nil 517 } 518 519 func (c *client) Status(ctx context.Context, containerID string) (Status, error) { 520 ctr := c.getContainer(containerID) 521 if ctr == nil { 522 return StatusUnknown, errors.WithStack(newNotFoundError("no such container")) 523 } 524 525 t := ctr.getTask() 526 if t == nil { 527 return StatusUnknown, errors.WithStack(newNotFoundError("no such task")) 528 } 529 530 s, err := t.Status(ctx) 531 if err != nil { 532 return StatusUnknown, err 533 } 534 535 return Status(s.Status), nil 536 } 537 538 func (c *client) CreateCheckpoint(ctx context.Context, containerID, checkpointDir string, exit bool) error { 539 p, err := c.getProcess(containerID, InitProcessName) 540 if err != nil { 541 return err 542 } 543 544 img, err := p.(containerd.Task).Checkpoint(ctx) 545 if err != nil { 546 return err 547 } 548 // Whatever happens, delete the checkpoint from containerd 549 defer func() { 550 err := c.getRemote().ImageService().Delete(context.Background(), img.Name()) 551 if err != nil { 552 c.logger.WithError(err).WithField("digest", img.Target().Digest). 553 Warnf("failed to delete checkpoint image") 554 } 555 }() 556 557 b, err := content.ReadBlob(ctx, c.getRemote().ContentStore(), img.Target().Digest) 558 if err != nil { 559 return wrapSystemError(errors.Wrapf(err, "failed to retrieve checkpoint data")) 560 } 561 var index v1.Index 562 if err := json.Unmarshal(b, &index); err != nil { 563 return wrapSystemError(errors.Wrapf(err, "failed to decode checkpoint data")) 564 } 565 566 var cpDesc *v1.Descriptor 567 for _, m := range index.Manifests { 568 if m.MediaType == images.MediaTypeContainerd1Checkpoint { 569 cpDesc = &m 570 break 571 } 572 } 573 if cpDesc == nil { 574 return wrapSystemError(errors.Wrapf(err, "invalid checkpoint")) 575 } 576 577 rat, err := c.getRemote().ContentStore().ReaderAt(ctx, cpDesc.Digest) 578 if err != nil { 579 return wrapSystemError(errors.Wrapf(err, "failed to get checkpoint reader")) 580 } 581 defer rat.Close() 582 _, err = archive.Apply(ctx, checkpointDir, content.NewReader(rat)) 583 if err != nil { 584 return wrapSystemError(errors.Wrapf(err, "failed to read checkpoint reader")) 585 } 586 587 return err 588 } 589 590 func (c *client) getContainer(id string) *container { 591 c.RLock() 592 ctr := c.containers[id] 593 c.RUnlock() 594 595 return ctr 596 } 597 598 func (c *client) removeContainer(id string) { 599 c.Lock() 600 delete(c.containers, id) 601 c.Unlock() 602 } 603 604 func (c *client) getProcess(containerID, processID string) (containerd.Process, error) { 605 ctr := c.getContainer(containerID) 606 if ctr == nil { 607 return nil, errors.WithStack(newNotFoundError("no such container")) 608 } 609 610 t := ctr.getTask() 611 if t == nil { 612 return nil, errors.WithStack(newNotFoundError("container is not running")) 613 } 614 if processID == InitProcessName { 615 return t, nil 616 } 617 618 p := ctr.getProcess(processID) 619 if p == nil { 620 return nil, errors.WithStack(newNotFoundError("no such exec")) 621 } 622 return p, nil 623 } 624 625 // createIO creates the io to be used by a process 626 // This needs to get a pointer to interface as upon closure the process may not have yet been registered 627 func (c *client) createIO(fifos *cio.FIFOSet, containerID, processID string, stdinCloseSync chan struct{}, attachStdio StdioCallback) (cio.IO, error) { 628 io, err := newIOPipe(fifos) 629 if err != nil { 630 return nil, err 631 } 632 633 if io.Stdin != nil { 634 var ( 635 err error 636 stdinOnce sync.Once 637 ) 638 pipe := io.Stdin 639 io.Stdin = ioutils.NewWriteCloserWrapper(pipe, func() error { 640 stdinOnce.Do(func() { 641 err = pipe.Close() 642 // Do the rest in a new routine to avoid a deadlock if the 643 // Exec/Start call failed. 644 go func() { 645 <-stdinCloseSync 646 p, err := c.getProcess(containerID, processID) 647 if err == nil { 648 err = p.CloseIO(context.Background(), containerd.WithStdinCloser) 649 if err != nil && strings.Contains(err.Error(), "transport is closing") { 650 err = nil 651 } 652 } 653 }() 654 }) 655 return err 656 }) 657 } 658 659 rio, err := attachStdio(io) 660 if err != nil { 661 io.Cancel() 662 io.Close() 663 } 664 return rio, err 665 } 666 667 func (c *client) processEvent(ctr *container, et EventType, ei EventInfo) { 668 c.eventQ.append(ei.ContainerID, func() { 669 err := c.backend.ProcessEvent(ei.ContainerID, et, ei) 670 if err != nil { 671 c.logger.WithError(err).WithFields(logrus.Fields{ 672 "container": ei.ContainerID, 673 "event": et, 674 "event-info": ei, 675 }).Error("failed to process event") 676 } 677 678 if et == EventExit && ei.ProcessID != ei.ContainerID { 679 p := ctr.getProcess(ei.ProcessID) 680 if p == nil { 681 c.logger.WithError(errors.New("no such process")). 682 WithFields(logrus.Fields{ 683 "container": ei.ContainerID, 684 "process": ei.ProcessID, 685 }).Error("exit event") 686 return 687 } 688 _, err = p.Delete(context.Background()) 689 if err != nil { 690 c.logger.WithError(err).WithFields(logrus.Fields{ 691 "container": ei.ContainerID, 692 "process": ei.ProcessID, 693 }).Warn("failed to delete process") 694 } 695 ctr.deleteProcess(ei.ProcessID) 696 697 ctr := c.getContainer(ei.ContainerID) 698 if ctr == nil { 699 c.logger.WithFields(logrus.Fields{ 700 "container": ei.ContainerID, 701 }).Error("failed to find container") 702 } else { 703 rmFIFOSet(newFIFOSet(ctr.bundleDir, ei.ContainerID, ei.ProcessID, true, false)) 704 } 705 } 706 }) 707 } 708 709 func (c *client) processEventStream(ctx context.Context) { 710 var ( 711 err error 712 eventStream eventsapi.Events_SubscribeClient 713 ev *eventsapi.Envelope 714 et EventType 715 ei EventInfo 716 ctr *container 717 ) 718 defer func() { 719 if err != nil { 720 select { 721 case <-ctx.Done(): 722 c.logger.WithError(ctx.Err()). 723 Info("stopping event stream following graceful shutdown") 724 default: 725 go c.processEventStream(ctx) 726 } 727 } 728 }() 729 730 eventStream, err = c.getRemote().EventService().Subscribe(ctx, &eventsapi.SubscribeRequest{ 731 Filters: []string{ 732 // Filter on both namespace *and* topic. To create an "and" filter, 733 // this must be a single, comma-separated string 734 "namespace==" + c.namespace + ",topic~=|^/tasks/|", 735 }, 736 }, grpc.FailFast(false)) 737 if err != nil { 738 return 739 } 740 741 c.logger.WithField("namespace", c.namespace).Debug("processing event stream") 742 743 var oomKilled bool 744 for { 745 ev, err = eventStream.Recv() 746 if err != nil { 747 errStatus, ok := status.FromError(err) 748 if !ok || errStatus.Code() != codes.Canceled { 749 c.logger.WithError(err).Error("failed to get event") 750 } 751 return 752 } 753 754 if ev.Event == nil { 755 c.logger.WithField("event", ev).Warn("invalid event") 756 continue 757 } 758 759 v, err := typeurl.UnmarshalAny(ev.Event) 760 if err != nil { 761 c.logger.WithError(err).WithField("event", ev).Warn("failed to unmarshal event") 762 continue 763 } 764 765 c.logger.WithField("topic", ev.Topic).Debug("event") 766 767 switch t := v.(type) { 768 case *events.TaskCreate: 769 et = EventCreate 770 ei = EventInfo{ 771 ContainerID: t.ContainerID, 772 ProcessID: t.ContainerID, 773 Pid: t.Pid, 774 } 775 case *events.TaskStart: 776 et = EventStart 777 ei = EventInfo{ 778 ContainerID: t.ContainerID, 779 ProcessID: t.ContainerID, 780 Pid: t.Pid, 781 } 782 case *events.TaskExit: 783 et = EventExit 784 ei = EventInfo{ 785 ContainerID: t.ContainerID, 786 ProcessID: t.ID, 787 Pid: t.Pid, 788 ExitCode: t.ExitStatus, 789 ExitedAt: t.ExitedAt, 790 } 791 case *events.TaskOOM: 792 et = EventOOM 793 ei = EventInfo{ 794 ContainerID: t.ContainerID, 795 OOMKilled: true, 796 } 797 oomKilled = true 798 case *events.TaskExecAdded: 799 et = EventExecAdded 800 ei = EventInfo{ 801 ContainerID: t.ContainerID, 802 ProcessID: t.ExecID, 803 } 804 case *events.TaskExecStarted: 805 et = EventExecStarted 806 ei = EventInfo{ 807 ContainerID: t.ContainerID, 808 ProcessID: t.ExecID, 809 Pid: t.Pid, 810 } 811 case *events.TaskPaused: 812 et = EventPaused 813 ei = EventInfo{ 814 ContainerID: t.ContainerID, 815 } 816 case *events.TaskResumed: 817 et = EventResumed 818 ei = EventInfo{ 819 ContainerID: t.ContainerID, 820 } 821 default: 822 c.logger.WithFields(logrus.Fields{ 823 "topic": ev.Topic, 824 "type": reflect.TypeOf(t)}, 825 ).Info("ignoring event") 826 continue 827 } 828 829 ctr = c.getContainer(ei.ContainerID) 830 if ctr == nil { 831 c.logger.WithField("container", ei.ContainerID).Warn("unknown container") 832 continue 833 } 834 835 if oomKilled { 836 ctr.setOOMKilled(true) 837 oomKilled = false 838 } 839 ei.OOMKilled = ctr.getOOMKilled() 840 841 c.processEvent(ctr, et, ei) 842 } 843 } 844 845 func (c *client) writeContent(ctx context.Context, mediaType, ref string, r io.Reader) (*types.Descriptor, error) { 846 writer, err := c.getRemote().ContentStore().Writer(ctx, ref, 0, "") 847 if err != nil { 848 return nil, err 849 } 850 defer writer.Close() 851 size, err := io.Copy(writer, r) 852 if err != nil { 853 return nil, err 854 } 855 labels := map[string]string{ 856 "containerd.io/gc.root": time.Now().UTC().Format(time.RFC3339), 857 } 858 if err := writer.Commit(ctx, 0, "", content.WithLabels(labels)); err != nil { 859 return nil, err 860 } 861 return &types.Descriptor{ 862 MediaType: mediaType, 863 Digest: writer.Digest(), 864 Size_: size, 865 }, nil 866 } 867 868 func wrapError(err error) error { 869 if err == nil { 870 return nil 871 } 872 873 switch { 874 case errdefs.IsNotFound(err): 875 return wrapNotFoundError(err) 876 } 877 878 msg := err.Error() 879 for _, s := range []string{"container does not exist", "not found", "no such container"} { 880 if strings.Contains(msg, s) { 881 return wrapNotFoundError(err) 882 } 883 } 884 return err 885 }