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