github.com/demonoid81/containerd@v1.3.4/container_linux_test.go (about) 1 // +build linux 2 3 /* 4 Copyright The containerd Authors. 5 6 Licensed under the Apache License, Version 2.0 (the "License"); 7 you may not use this file except in compliance with the License. 8 You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 See the License for the specific language governing permissions and 16 limitations under the License. 17 */ 18 19 package containerd 20 21 import ( 22 "bytes" 23 "context" 24 "fmt" 25 "io" 26 "io/ioutil" 27 "os" 28 "os/exec" 29 "path/filepath" 30 "runtime" 31 "strings" 32 "sync" 33 "syscall" 34 "testing" 35 "time" 36 37 "github.com/containerd/cgroups" 38 "github.com/containerd/containerd/cio" 39 "github.com/containerd/containerd/containers" 40 "github.com/containerd/containerd/errdefs" 41 "github.com/containerd/containerd/oci" 42 "github.com/containerd/containerd/plugin" 43 "github.com/containerd/containerd/runtime/linux/runctypes" 44 "github.com/containerd/containerd/runtime/v2/runc/options" 45 "github.com/containerd/containerd/sys" 46 specs "github.com/opencontainers/runtime-spec/specs-go" 47 "github.com/pkg/errors" 48 "golang.org/x/sys/unix" 49 ) 50 51 func TestTaskUpdate(t *testing.T) { 52 t.Parallel() 53 54 client, err := newClient(t, address) 55 if err != nil { 56 t.Fatal(err) 57 } 58 defer client.Close() 59 60 var ( 61 ctx, cancel = testContext(t) 62 id = t.Name() 63 ) 64 defer cancel() 65 66 image, err := client.GetImage(ctx, testImage) 67 if err != nil { 68 t.Fatal(err) 69 } 70 limit := int64(32 * 1024 * 1024) 71 memory := func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error { 72 s.Linux.Resources.Memory = &specs.LinuxMemory{ 73 Limit: &limit, 74 } 75 return nil 76 } 77 container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), 78 WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "30"), memory)) 79 if err != nil { 80 t.Fatal(err) 81 } 82 defer container.Delete(ctx, WithSnapshotCleanup) 83 84 task, err := container.NewTask(ctx, empty()) 85 if err != nil { 86 t.Fatal(err) 87 } 88 defer task.Delete(ctx) 89 90 statusC, err := task.Wait(ctx) 91 if err != nil { 92 t.Fatal(err) 93 } 94 95 // check that the task has a limit of 32mb 96 cgroup, err := cgroups.Load(cgroups.V1, cgroups.PidPath(int(task.Pid()))) 97 if err != nil { 98 t.Fatal(err) 99 } 100 stat, err := cgroup.Stat(cgroups.IgnoreNotExist) 101 if err != nil { 102 t.Fatal(err) 103 } 104 if int64(stat.Memory.Usage.Limit) != limit { 105 t.Fatalf("expected memory limit to be set to %d but received %d", limit, stat.Memory.Usage.Limit) 106 } 107 limit = 64 * 1024 * 1024 108 if err := task.Update(ctx, WithResources(&specs.LinuxResources{ 109 Memory: &specs.LinuxMemory{ 110 Limit: &limit, 111 }, 112 })); err != nil { 113 t.Error(err) 114 } 115 // check that the task has a limit of 64mb 116 if stat, err = cgroup.Stat(cgroups.IgnoreNotExist); err != nil { 117 t.Fatal(err) 118 } 119 if int64(stat.Memory.Usage.Limit) != limit { 120 t.Errorf("expected memory limit to be set to %d but received %d", limit, stat.Memory.Usage.Limit) 121 } 122 if err := task.Kill(ctx, unix.SIGKILL); err != nil { 123 t.Fatal(err) 124 } 125 126 <-statusC 127 } 128 129 func TestShimInCgroup(t *testing.T) { 130 t.Parallel() 131 132 client, err := newClient(t, address) 133 if err != nil { 134 t.Fatal(err) 135 } 136 defer client.Close() 137 var ( 138 ctx, cancel = testContext(t) 139 id = t.Name() 140 ) 141 defer cancel() 142 143 image, err := client.GetImage(ctx, testImage) 144 if err != nil { 145 t.Fatal(err) 146 } 147 container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), oci.WithProcessArgs("sleep", "30"))) 148 if err != nil { 149 t.Fatal(err) 150 } 151 defer container.Delete(ctx, WithSnapshotCleanup) 152 // create a cgroup for the shim to use 153 path := "/containerd/shim" 154 cg, err := cgroups.New(cgroups.V1, cgroups.StaticPath(path), &specs.LinuxResources{}) 155 if err != nil { 156 t.Fatal(err) 157 } 158 defer cg.Delete() 159 160 task, err := container.NewTask(ctx, empty(), WithShimCgroup(path)) 161 if err != nil { 162 t.Fatal(err) 163 } 164 defer task.Delete(ctx) 165 166 statusC, err := task.Wait(ctx) 167 if err != nil { 168 t.Fatal(err) 169 } 170 171 // check to see if the shim is inside the cgroup 172 processes, err := cg.Processes(cgroups.Devices, false) 173 if err != nil { 174 t.Fatal(err) 175 } 176 if len(processes) == 0 { 177 t.Errorf("created cgroup should have at least one process inside: %d", len(processes)) 178 } 179 if err := task.Kill(ctx, unix.SIGKILL); err != nil { 180 t.Fatal(err) 181 } 182 183 <-statusC 184 } 185 186 func TestDaemonRestart(t *testing.T) { 187 client, err := newClient(t, address) 188 if err != nil { 189 t.Fatal(err) 190 } 191 defer client.Close() 192 193 var ( 194 image Image 195 ctx, cancel = testContext(t) 196 id = t.Name() 197 ) 198 defer cancel() 199 200 image, err = client.GetImage(ctx, testImage) 201 if err != nil { 202 t.Fatal(err) 203 } 204 205 container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "30"))) 206 if err != nil { 207 t.Fatal(err) 208 } 209 defer container.Delete(ctx, WithSnapshotCleanup) 210 211 task, err := container.NewTask(ctx, empty()) 212 if err != nil { 213 t.Fatal(err) 214 } 215 defer task.Delete(ctx) 216 217 statusC, err := task.Wait(ctx) 218 if err != nil { 219 t.Fatal(err) 220 } 221 222 if err := task.Start(ctx); err != nil { 223 t.Fatal(err) 224 } 225 226 var exitStatus ExitStatus 227 if err := ctrd.Restart(func() { 228 exitStatus = <-statusC 229 }); err != nil { 230 t.Fatal(err) 231 } 232 233 if exitStatus.Error() == nil { 234 t.Errorf(`first task.Wait() should have failed with "transport is closing"`) 235 } 236 237 waitCtx, waitCancel := context.WithTimeout(ctx, 2*time.Second) 238 serving, err := client.IsServing(waitCtx) 239 waitCancel() 240 if !serving { 241 t.Fatalf("containerd did not start within 2s: %v", err) 242 } 243 244 statusC, err = task.Wait(ctx) 245 if err != nil { 246 t.Fatal(err) 247 } 248 249 if err := task.Kill(ctx, syscall.SIGKILL); err != nil { 250 t.Fatal(err) 251 } 252 253 <-statusC 254 } 255 256 func TestShimDoesNotLeakPipes(t *testing.T) { 257 containerdPid := ctrd.cmd.Process.Pid 258 initialPipes, err := numPipes(containerdPid) 259 if err != nil { 260 t.Fatal(err) 261 } 262 263 client, err := newClient(t, address) 264 if err != nil { 265 t.Fatal(err) 266 } 267 defer client.Close() 268 269 var ( 270 image Image 271 ctx, cancel = testContext(t) 272 id = t.Name() 273 ) 274 defer cancel() 275 276 image, err = client.GetImage(ctx, testImage) 277 if err != nil { 278 t.Fatal(err) 279 } 280 281 container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "30"))) 282 if err != nil { 283 t.Fatal(err) 284 } 285 286 task, err := container.NewTask(ctx, empty()) 287 if err != nil { 288 t.Fatal(err) 289 } 290 291 exitChannel, err := task.Wait(ctx) 292 if err != nil { 293 t.Fatal(err) 294 } 295 296 if err := task.Start(ctx); err != nil { 297 t.Fatal(err) 298 } 299 300 if err := task.Kill(ctx, syscall.SIGKILL); err != nil { 301 t.Fatal(err) 302 } 303 304 <-exitChannel 305 306 if _, err := task.Delete(ctx); err != nil { 307 t.Fatal(err) 308 } 309 310 if err := container.Delete(ctx, WithSnapshotCleanup); err != nil { 311 t.Fatal(err) 312 } 313 314 currentPipes, err := numPipes(containerdPid) 315 if err != nil { 316 t.Fatal(err) 317 } 318 319 if initialPipes != currentPipes { 320 t.Errorf("Pipes have leaked after container has been deleted. Initially there were %d pipes, after container deletion there were %d pipes", initialPipes, currentPipes) 321 } 322 } 323 324 func numPipes(pid int) (int, error) { 325 cmd := exec.Command("sh", "-c", fmt.Sprintf("lsof -p %d | grep FIFO", pid)) 326 327 var stdout bytes.Buffer 328 cmd.Stdout = &stdout 329 if err := cmd.Run(); err != nil { 330 return 0, err 331 } 332 return strings.Count(stdout.String(), "\n"), nil 333 } 334 335 func TestDaemonReconnectsToShimIOPipesOnRestart(t *testing.T) { 336 client, err := newClient(t, address) 337 if err != nil { 338 t.Fatal(err) 339 } 340 defer client.Close() 341 342 var ( 343 image Image 344 ctx, cancel = testContext(t) 345 id = t.Name() 346 ) 347 defer cancel() 348 349 image, err = client.GetImage(ctx, testImage) 350 if err != nil { 351 t.Fatal(err) 352 } 353 354 container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "30"))) 355 if err != nil { 356 t.Fatal(err) 357 } 358 defer container.Delete(ctx, WithSnapshotCleanup) 359 360 task, err := container.NewTask(ctx, empty()) 361 if err != nil { 362 t.Fatal(err) 363 } 364 defer task.Delete(ctx) 365 366 _, err = task.Wait(ctx) 367 if err != nil { 368 t.Fatal(err) 369 } 370 371 if err := task.Start(ctx); err != nil { 372 t.Fatal(err) 373 } 374 375 if err := ctrd.Restart(nil); err != nil { 376 t.Fatal(err) 377 } 378 379 waitCtx, waitCancel := context.WithTimeout(ctx, 2*time.Second) 380 serving, err := client.IsServing(waitCtx) 381 waitCancel() 382 if !serving { 383 t.Fatalf("containerd did not start within 2s: %v", err) 384 } 385 386 // After we restared containerd we write some messages to the log pipes, simulating shim writing stuff there. 387 // Then we make sure that these messages are available on the containerd log thus proving that the server reconnected to the log pipes 388 runtimeVersion := getRuntimeVersion() 389 logDirPath := getLogDirPath(runtimeVersion, id) 390 391 switch runtimeVersion { 392 case "v1": 393 writeToFile(t, filepath.Join(logDirPath, "shim.stdout.log"), fmt.Sprintf("%s writing to stdout\n", id)) 394 writeToFile(t, filepath.Join(logDirPath, "shim.stderr.log"), fmt.Sprintf("%s writing to stderr\n", id)) 395 case "v2": 396 writeToFile(t, filepath.Join(logDirPath, "log"), fmt.Sprintf("%s writing to log\n", id)) 397 } 398 399 statusC, err := task.Wait(ctx) 400 if err != nil { 401 t.Fatal(err) 402 } 403 404 if err := task.Kill(ctx, syscall.SIGKILL); err != nil { 405 t.Fatal(err) 406 } 407 408 <-statusC 409 410 stdioContents, err := ioutil.ReadFile(ctrdStdioFilePath) 411 if err != nil { 412 t.Fatal(err) 413 } 414 415 switch runtimeVersion { 416 case "v1": 417 if !strings.Contains(string(stdioContents), fmt.Sprintf("%s writing to stdout", id)) { 418 t.Fatal("containerd did not connect to the shim stdout pipe") 419 } 420 if !strings.Contains(string(stdioContents), fmt.Sprintf("%s writing to stderr", id)) { 421 t.Fatal("containerd did not connect to the shim stderr pipe") 422 } 423 case "v2": 424 if !strings.Contains(string(stdioContents), fmt.Sprintf("%s writing to log", id)) { 425 t.Fatal("containerd did not connect to the shim log pipe") 426 } 427 } 428 } 429 430 func writeToFile(t *testing.T, filePath, message string) { 431 writer, err := os.OpenFile(filePath, os.O_WRONLY, 0600) 432 if err != nil { 433 t.Fatal(err) 434 } 435 if _, err := writer.WriteString(message); err != nil { 436 t.Fatal(err) 437 } 438 if err := writer.Close(); err != nil { 439 t.Fatal(err) 440 } 441 } 442 443 func getLogDirPath(runtimeVersion, id string) string { 444 switch runtimeVersion { 445 case "v1": 446 return filepath.Join(defaultRoot, plugin.RuntimeLinuxV1, testNamespace, id) 447 case "v2": 448 return filepath.Join(defaultState, "io.containerd.runtime.v2.task", testNamespace, id) 449 default: 450 panic(fmt.Errorf("Unsupported runtime version %s", runtimeVersion)) 451 } 452 } 453 454 func getRuntimeVersion() string { 455 switch rt := os.Getenv("TEST_RUNTIME"); rt { 456 case plugin.RuntimeRuncV1, plugin.RuntimeRuncV2: 457 return "v2" 458 default: 459 return "v1" 460 } 461 } 462 463 func TestContainerPTY(t *testing.T) { 464 t.Parallel() 465 466 client, err := newClient(t, address) 467 if err != nil { 468 t.Fatal(err) 469 } 470 defer client.Close() 471 472 var ( 473 image Image 474 ctx, cancel = testContext(t) 475 id = t.Name() 476 ) 477 defer cancel() 478 479 image, err = client.GetImage(ctx, testImage) 480 if err != nil { 481 t.Fatal(err) 482 } 483 484 container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), oci.WithTTY, withProcessArgs("echo", "hello"))) 485 if err != nil { 486 t.Fatal(err) 487 } 488 defer container.Delete(ctx, WithSnapshotCleanup) 489 490 direct, err := newDirectIO(ctx, true) 491 if err != nil { 492 t.Fatal(err) 493 } 494 defer direct.Delete() 495 var ( 496 wg sync.WaitGroup 497 buf = bytes.NewBuffer(nil) 498 ) 499 wg.Add(1) 500 go func() { 501 defer wg.Done() 502 io.Copy(buf, direct.Stdout) 503 }() 504 505 task, err := container.NewTask(ctx, direct.IOCreate) 506 if err != nil { 507 t.Fatal(err) 508 } 509 defer task.Delete(ctx) 510 511 status, err := task.Wait(ctx) 512 if err != nil { 513 t.Error(err) 514 } 515 516 if err := task.Start(ctx); err != nil { 517 t.Fatal(err) 518 } 519 520 <-status 521 wg.Wait() 522 523 if err := direct.Close(); err != nil { 524 t.Error(err) 525 } 526 527 out := buf.String() 528 if !strings.ContainsAny(fmt.Sprintf("%#q", out), `\x00`) { 529 t.Fatal(`expected \x00 in output`) 530 } 531 } 532 533 func TestContainerAttach(t *testing.T) { 534 t.Parallel() 535 536 if runtime.GOOS == "windows" { 537 // On windows, closing the write side of the pipe closes the read 538 // side, sending an EOF to it and preventing reopening it. 539 // Hence this test will always fails on windows 540 t.Skip("invalid logic on windows") 541 } 542 543 client, err := newClient(t, address) 544 if err != nil { 545 t.Fatal(err) 546 } 547 defer client.Close() 548 549 var ( 550 image Image 551 ctx, cancel = testContext(t) 552 id = t.Name() 553 ) 554 defer cancel() 555 556 image, err = client.GetImage(ctx, testImage) 557 if err != nil { 558 t.Fatal(err) 559 } 560 561 container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withCat())) 562 if err != nil { 563 t.Fatal(err) 564 } 565 defer container.Delete(ctx, WithSnapshotCleanup) 566 567 expected := "hello" + newLine 568 569 direct, err := newDirectIO(ctx, false) 570 if err != nil { 571 t.Fatal(err) 572 } 573 defer direct.Delete() 574 var ( 575 wg sync.WaitGroup 576 buf = bytes.NewBuffer(nil) 577 ) 578 wg.Add(1) 579 go func() { 580 defer wg.Done() 581 io.Copy(buf, direct.Stdout) 582 }() 583 584 task, err := container.NewTask(ctx, direct.IOCreate) 585 if err != nil { 586 t.Fatal(err) 587 } 588 defer task.Delete(ctx) 589 590 status, err := task.Wait(ctx) 591 if err != nil { 592 t.Error(err) 593 } 594 595 if err := task.Start(ctx); err != nil { 596 t.Fatal(err) 597 } 598 599 if _, err := fmt.Fprint(direct.Stdin, expected); err != nil { 600 t.Error(err) 601 } 602 603 // load the container and re-load the task 604 if container, err = client.LoadContainer(ctx, id); err != nil { 605 t.Fatal(err) 606 } 607 608 if task, err = container.Task(ctx, direct.IOAttach); err != nil { 609 t.Fatal(err) 610 } 611 612 if _, err := fmt.Fprint(direct.Stdin, expected); err != nil { 613 t.Error(err) 614 } 615 616 direct.Stdin.Close() 617 618 if err := task.CloseIO(ctx, WithStdinCloser); err != nil { 619 t.Error(err) 620 } 621 622 <-status 623 624 wg.Wait() 625 if _, err := task.Delete(ctx); err != nil { 626 t.Error(err) 627 } 628 629 output := buf.String() 630 631 // we wrote the same thing after attach 632 expected = expected + expected 633 if output != expected { 634 t.Errorf("expected output %q but received %q", expected, output) 635 } 636 } 637 638 func newDirectIO(ctx context.Context, terminal bool) (*directIO, error) { 639 fifos, err := cio.NewFIFOSetInDir("", "", terminal) 640 if err != nil { 641 return nil, err 642 } 643 dio, err := cio.NewDirectIO(ctx, fifos) 644 if err != nil { 645 return nil, err 646 } 647 return &directIO{DirectIO: *dio}, nil 648 } 649 650 type directIO struct { 651 cio.DirectIO 652 } 653 654 // ioCreate returns IO available for use with task creation 655 func (f *directIO) IOCreate(id string) (cio.IO, error) { 656 return f, nil 657 } 658 659 // ioAttach returns IO available for use with task attachment 660 func (f *directIO) IOAttach(set *cio.FIFOSet) (cio.IO, error) { 661 return f, nil 662 } 663 664 func (f *directIO) Cancel() { 665 // nothing to cancel as all operations are handled externally 666 } 667 668 // Close closes all open fds 669 func (f *directIO) Close() error { 670 err := f.Stdin.Close() 671 if err2 := f.Stdout.Close(); err == nil { 672 err = err2 673 } 674 if err2 := f.Stderr.Close(); err == nil { 675 err = err2 676 } 677 return err 678 } 679 680 // Delete removes the underlying directory containing fifos 681 func (f *directIO) Delete() error { 682 return f.DirectIO.Close() 683 } 684 685 func TestContainerUsername(t *testing.T) { 686 t.Parallel() 687 688 client, err := newClient(t, address) 689 if err != nil { 690 t.Fatal(err) 691 } 692 defer client.Close() 693 694 var ( 695 image Image 696 ctx, cancel = testContext(t) 697 id = t.Name() 698 ) 699 defer cancel() 700 701 image, err = client.GetImage(ctx, testImage) 702 if err != nil { 703 t.Fatal(err) 704 } 705 direct, err := newDirectIO(ctx, false) 706 if err != nil { 707 t.Fatal(err) 708 } 709 defer direct.Delete() 710 var ( 711 wg sync.WaitGroup 712 buf = bytes.NewBuffer(nil) 713 ) 714 wg.Add(1) 715 go func() { 716 defer wg.Done() 717 io.Copy(buf, direct.Stdout) 718 }() 719 720 // squid user in the alpine image has a uid of 31 721 container, err := client.NewContainer(ctx, id, 722 WithNewSnapshot(id, image), 723 WithNewSpec(oci.WithImageConfig(image), oci.WithUsername("squid"), oci.WithProcessArgs("id", "-u")), 724 ) 725 if err != nil { 726 t.Fatal(err) 727 } 728 defer container.Delete(ctx, WithSnapshotCleanup) 729 730 task, err := container.NewTask(ctx, direct.IOCreate) 731 if err != nil { 732 t.Fatal(err) 733 } 734 defer task.Delete(ctx) 735 736 statusC, err := task.Wait(ctx) 737 if err != nil { 738 t.Fatal(err) 739 } 740 741 if err := task.Start(ctx); err != nil { 742 t.Fatal(err) 743 } 744 <-statusC 745 746 wg.Wait() 747 748 output := strings.TrimSuffix(buf.String(), "\n") 749 if output != "31" { 750 t.Errorf("expected squid uid to be 31 but received %q", output) 751 } 752 } 753 754 func TestContainerUser(t *testing.T) { 755 t.Parallel() 756 t.Run("UserNameAndGroupName", func(t *testing.T) { testContainerUser(t, "squid:squid", "31:31") }) 757 t.Run("UserIDAndGroupName", func(t *testing.T) { testContainerUser(t, "1001:squid", "1001:31") }) 758 t.Run("UserNameAndGroupID", func(t *testing.T) { testContainerUser(t, "squid:1002", "31:1002") }) 759 t.Run("UserIDAndGroupID", func(t *testing.T) { testContainerUser(t, "1001:1002", "1001:1002") }) 760 } 761 762 func testContainerUser(t *testing.T, userstr, expectedOutput string) { 763 client, err := newClient(t, address) 764 if err != nil { 765 t.Fatal(err) 766 } 767 defer client.Close() 768 769 var ( 770 image Image 771 ctx, cancel = testContext(t) 772 id = strings.Replace(t.Name(), "/", "_", -1) 773 ) 774 defer cancel() 775 776 image, err = client.GetImage(ctx, testImage) 777 if err != nil { 778 t.Fatal(err) 779 } 780 direct, err := newDirectIO(ctx, false) 781 if err != nil { 782 t.Fatal(err) 783 } 784 defer direct.Delete() 785 var ( 786 wg sync.WaitGroup 787 buf = bytes.NewBuffer(nil) 788 ) 789 wg.Add(1) 790 go func() { 791 defer wg.Done() 792 io.Copy(buf, direct.Stdout) 793 }() 794 795 container, err := client.NewContainer(ctx, id, 796 WithNewSnapshot(id, image), 797 WithNewSpec(oci.WithImageConfig(image), oci.WithUser(userstr), oci.WithProcessArgs("sh", "-c", "echo $(id -u):$(id -g)")), 798 ) 799 if err != nil { 800 t.Fatal(err) 801 } 802 defer container.Delete(ctx, WithSnapshotCleanup) 803 804 task, err := container.NewTask(ctx, direct.IOCreate) 805 if err != nil { 806 t.Fatal(err) 807 } 808 defer task.Delete(ctx) 809 810 statusC, err := task.Wait(ctx) 811 if err != nil { 812 t.Fatal(err) 813 } 814 815 if err := task.Start(ctx); err != nil { 816 t.Fatal(err) 817 } 818 <-statusC 819 820 wg.Wait() 821 822 output := strings.TrimSuffix(buf.String(), "\n") 823 if output != expectedOutput { 824 t.Errorf("expected uid:gid to be %q, but received %q", expectedOutput, output) 825 } 826 } 827 828 func TestContainerAttachProcess(t *testing.T) { 829 t.Parallel() 830 831 if runtime.GOOS == "windows" { 832 // On windows, closing the write side of the pipe closes the read 833 // side, sending an EOF to it and preventing reopening it. 834 // Hence this test will always fails on windows 835 t.Skip("invalid logic on windows") 836 } 837 838 client, err := newClient(t, address) 839 if err != nil { 840 t.Fatal(err) 841 } 842 defer client.Close() 843 844 var ( 845 image Image 846 ctx, cancel = testContext(t) 847 id = t.Name() 848 ) 849 defer cancel() 850 851 image, err = client.GetImage(ctx, testImage) 852 if err != nil { 853 t.Fatal(err) 854 } 855 856 container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "100"))) 857 if err != nil { 858 t.Fatal(err) 859 } 860 defer container.Delete(ctx, WithSnapshotCleanup) 861 862 expected := "hello" + newLine 863 864 // creating IO early for easy resource cleanup 865 direct, err := newDirectIO(ctx, false) 866 if err != nil { 867 t.Fatal(err) 868 } 869 defer direct.Delete() 870 var ( 871 wg sync.WaitGroup 872 buf = bytes.NewBuffer(nil) 873 ) 874 wg.Add(1) 875 go func() { 876 defer wg.Done() 877 io.Copy(buf, direct.Stdout) 878 }() 879 880 task, err := container.NewTask(ctx, empty()) 881 if err != nil { 882 t.Fatal(err) 883 } 884 defer task.Delete(ctx) 885 886 status, err := task.Wait(ctx) 887 if err != nil { 888 t.Error(err) 889 } 890 891 if err := task.Start(ctx); err != nil { 892 t.Fatal(err) 893 } 894 895 spec, err := container.Spec(ctx) 896 if err != nil { 897 t.Fatal(err) 898 } 899 900 processSpec := spec.Process 901 processSpec.Args = []string{"cat"} 902 execID := t.Name() + "_exec" 903 process, err := task.Exec(ctx, execID, processSpec, direct.IOCreate) 904 if err != nil { 905 t.Fatal(err) 906 } 907 processStatusC, err := process.Wait(ctx) 908 if err != nil { 909 t.Fatal(err) 910 } 911 912 if err := process.Start(ctx); err != nil { 913 t.Fatal(err) 914 } 915 916 if _, err := fmt.Fprint(direct.Stdin, expected); err != nil { 917 t.Error(err) 918 } 919 920 if process, err = task.LoadProcess(ctx, execID, direct.IOAttach); err != nil { 921 t.Fatal(err) 922 } 923 924 if _, err := fmt.Fprint(direct.Stdin, expected); err != nil { 925 t.Error(err) 926 } 927 928 direct.Stdin.Close() 929 930 if err := process.CloseIO(ctx, WithStdinCloser); err != nil { 931 t.Error(err) 932 } 933 934 <-processStatusC 935 936 wg.Wait() 937 938 if err := task.Kill(ctx, syscall.SIGKILL); err != nil { 939 t.Error(err) 940 } 941 942 output := buf.String() 943 944 // we wrote the same thing after attach 945 expected = expected + expected 946 if output != expected { 947 t.Errorf("expected output %q but received %q", expected, output) 948 } 949 <-status 950 } 951 952 func TestContainerUserID(t *testing.T) { 953 t.Parallel() 954 955 client, err := newClient(t, address) 956 if err != nil { 957 t.Fatal(err) 958 } 959 defer client.Close() 960 961 var ( 962 image Image 963 ctx, cancel = testContext(t) 964 id = t.Name() 965 ) 966 defer cancel() 967 968 image, err = client.GetImage(ctx, testImage) 969 if err != nil { 970 t.Fatal(err) 971 } 972 direct, err := newDirectIO(ctx, false) 973 if err != nil { 974 t.Fatal(err) 975 } 976 defer direct.Delete() 977 var ( 978 wg sync.WaitGroup 979 buf = bytes.NewBuffer(nil) 980 ) 981 wg.Add(1) 982 go func() { 983 defer wg.Done() 984 io.Copy(buf, direct.Stdout) 985 }() 986 987 // adm user in the alpine image has a uid of 3 and gid of 4. 988 container, err := client.NewContainer(ctx, id, 989 WithNewSnapshot(id, image), 990 WithNewSpec(oci.WithImageConfig(image), oci.WithUserID(3), oci.WithProcessArgs("sh", "-c", "echo $(id -u):$(id -g)")), 991 ) 992 if err != nil { 993 t.Fatal(err) 994 } 995 defer container.Delete(ctx, WithSnapshotCleanup) 996 997 task, err := container.NewTask(ctx, direct.IOCreate) 998 if err != nil { 999 t.Fatal(err) 1000 } 1001 defer task.Delete(ctx) 1002 1003 statusC, err := task.Wait(ctx) 1004 if err != nil { 1005 t.Fatal(err) 1006 } 1007 1008 if err := task.Start(ctx); err != nil { 1009 t.Fatal(err) 1010 } 1011 <-statusC 1012 1013 wg.Wait() 1014 1015 output := strings.TrimSuffix(buf.String(), "\n") 1016 if output != "3:4" { 1017 t.Errorf("expected uid:gid to be 3:4, but received %q", output) 1018 } 1019 } 1020 1021 func TestContainerKillAll(t *testing.T) { 1022 t.Parallel() 1023 1024 client, err := newClient(t, address) 1025 if err != nil { 1026 t.Fatal(err) 1027 } 1028 defer client.Close() 1029 1030 var ( 1031 image Image 1032 ctx, cancel = testContext(t) 1033 id = t.Name() 1034 ) 1035 defer cancel() 1036 1037 image, err = client.GetImage(ctx, testImage) 1038 if err != nil { 1039 t.Fatal(err) 1040 } 1041 1042 container, err := client.NewContainer(ctx, id, 1043 WithNewSnapshot(id, image), 1044 WithNewSpec(oci.WithImageConfig(image), 1045 withProcessArgs("sh", "-c", "top"), 1046 oci.WithHostNamespace(specs.PIDNamespace), 1047 ), 1048 ) 1049 if err != nil { 1050 t.Fatal(err) 1051 } 1052 defer container.Delete(ctx, WithSnapshotCleanup) 1053 1054 stdout := bytes.NewBuffer(nil) 1055 task, err := container.NewTask(ctx, cio.NewCreator(withByteBuffers(stdout))) 1056 if err != nil { 1057 t.Fatal(err) 1058 } 1059 defer task.Delete(ctx) 1060 1061 statusC, err := task.Wait(ctx) 1062 if err != nil { 1063 t.Fatal(err) 1064 } 1065 1066 if err := task.Start(ctx); err != nil { 1067 t.Fatal(err) 1068 } 1069 1070 if err := task.Kill(ctx, syscall.SIGKILL, WithKillAll); err != nil { 1071 t.Error(err) 1072 } 1073 1074 <-statusC 1075 if _, err := task.Delete(ctx); err != nil { 1076 t.Fatal(err) 1077 } 1078 } 1079 1080 func TestDaemonRestartWithRunningShim(t *testing.T) { 1081 client, err := newClient(t, address) 1082 if err != nil { 1083 t.Fatal(err) 1084 } 1085 defer client.Close() 1086 1087 var ( 1088 image Image 1089 ctx, cancel = testContext(t) 1090 id = t.Name() 1091 ) 1092 defer cancel() 1093 1094 image, err = client.GetImage(ctx, testImage) 1095 if err != nil { 1096 t.Fatal(err) 1097 } 1098 container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), oci.WithProcessArgs("sleep", "100"))) 1099 if err != nil { 1100 t.Fatal(err) 1101 } 1102 defer container.Delete(ctx, WithSnapshotCleanup) 1103 1104 task, err := container.NewTask(ctx, empty()) 1105 if err != nil { 1106 t.Fatal(err) 1107 } 1108 defer task.Delete(ctx) 1109 1110 statusC, err := task.Wait(ctx) 1111 if err != nil { 1112 t.Error(err) 1113 } 1114 1115 pid := task.Pid() 1116 if pid < 1 { 1117 t.Fatalf("invalid task pid %d", pid) 1118 } 1119 1120 if err := task.Start(ctx); err != nil { 1121 t.Fatal(err) 1122 } 1123 1124 var exitStatus ExitStatus 1125 if err := ctrd.Restart(func() { 1126 exitStatus = <-statusC 1127 }); err != nil { 1128 t.Fatal(err) 1129 } 1130 1131 if exitStatus.Error() == nil { 1132 t.Errorf(`first task.Wait() should have failed with "transport is closing"`) 1133 } 1134 1135 waitCtx, cancel := context.WithTimeout(ctx, 1*time.Second) 1136 c, err := ctrd.waitForStart(waitCtx) 1137 cancel() 1138 if err != nil { 1139 t.Fatal(err) 1140 } 1141 c.Close() 1142 1143 statusC, err = task.Wait(ctx) 1144 if err != nil { 1145 t.Error(err) 1146 } 1147 1148 if err := task.Kill(ctx, syscall.SIGKILL); err != nil { 1149 t.Fatal(err) 1150 } 1151 1152 <-statusC 1153 1154 if err := unix.Kill(int(pid), 0); err != unix.ESRCH { 1155 t.Errorf("pid %d still exists", pid) 1156 } 1157 } 1158 1159 func TestContainerRuntimeOptionsv1(t *testing.T) { 1160 t.Parallel() 1161 1162 client, err := newClient(t, address) 1163 if err != nil { 1164 t.Fatal(err) 1165 } 1166 defer client.Close() 1167 1168 var ( 1169 image Image 1170 ctx, cancel = testContext(t) 1171 id = t.Name() 1172 ) 1173 defer cancel() 1174 1175 image, err = client.GetImage(ctx, testImage) 1176 if err != nil { 1177 t.Fatal(err) 1178 } 1179 1180 container, err := client.NewContainer( 1181 ctx, id, 1182 WithNewSnapshot(id, image), 1183 WithNewSpec(oci.WithImageConfig(image), withExitStatus(7)), 1184 WithRuntime(plugin.RuntimeLinuxV1, &runctypes.RuncOptions{Runtime: "no-runc"}), 1185 ) 1186 if err != nil { 1187 t.Fatal(err) 1188 } 1189 defer container.Delete(ctx, WithSnapshotCleanup) 1190 1191 task, err := container.NewTask(ctx, empty()) 1192 if err == nil { 1193 t.Errorf("task creation should have failed") 1194 task.Delete(ctx) 1195 return 1196 } 1197 if !strings.Contains(err.Error(), `"no-runc"`) { 1198 t.Errorf("task creation should have failed because of lack of executable. Instead failed with: %v", err.Error()) 1199 } 1200 } 1201 1202 func TestContainerRuntimeOptionsv2(t *testing.T) { 1203 t.Parallel() 1204 1205 client, err := newClient(t, address) 1206 if err != nil { 1207 t.Fatal(err) 1208 } 1209 defer client.Close() 1210 1211 var ( 1212 image Image 1213 ctx, cancel = testContext(t) 1214 id = t.Name() 1215 ) 1216 defer cancel() 1217 1218 image, err = client.GetImage(ctx, testImage) 1219 if err != nil { 1220 t.Fatal(err) 1221 } 1222 1223 container, err := client.NewContainer( 1224 ctx, id, 1225 WithNewSnapshot(id, image), 1226 WithNewSpec(oci.WithImageConfig(image), withExitStatus(7)), 1227 WithRuntime(plugin.RuntimeRuncV1, &options.Options{BinaryName: "no-runc"}), 1228 ) 1229 if err != nil { 1230 t.Fatal(err) 1231 } 1232 defer container.Delete(ctx, WithSnapshotCleanup) 1233 1234 task, err := container.NewTask(ctx, empty()) 1235 if err == nil { 1236 t.Errorf("task creation should have failed") 1237 task.Delete(ctx) 1238 return 1239 } 1240 if !strings.Contains(err.Error(), `"no-runc"`) { 1241 t.Errorf("task creation should have failed because of lack of executable. Instead failed with: %v", err.Error()) 1242 } 1243 } 1244 1245 func initContainerAndCheckChildrenDieOnKill(t *testing.T, opts ...oci.SpecOpts) { 1246 client, err := newClient(t, address) 1247 if err != nil { 1248 t.Fatal(err) 1249 } 1250 defer client.Close() 1251 1252 var ( 1253 image Image 1254 ctx, cancel = testContext(t) 1255 id = t.Name() 1256 ) 1257 defer cancel() 1258 1259 image, err = client.GetImage(ctx, testImage) 1260 if err != nil { 1261 t.Fatal(err) 1262 } 1263 1264 opts = append(opts, oci.WithImageConfig(image)) 1265 opts = append(opts, withProcessArgs("sh", "-c", "sleep 42; echo hi")) 1266 1267 container, err := client.NewContainer(ctx, id, 1268 WithNewSnapshot(id, image), 1269 WithNewSpec(opts...), 1270 ) 1271 if err != nil { 1272 t.Fatal(err) 1273 } 1274 defer container.Delete(ctx, WithSnapshotCleanup) 1275 1276 stdout := bytes.NewBuffer(nil) 1277 task, err := container.NewTask(ctx, cio.NewCreator(withByteBuffers(stdout))) 1278 if err != nil { 1279 t.Fatal(err) 1280 } 1281 defer task.Delete(ctx) 1282 1283 statusC, err := task.Wait(ctx) 1284 if err != nil { 1285 t.Fatal(err) 1286 } 1287 1288 if err := task.Start(ctx); err != nil { 1289 t.Fatal(err) 1290 } 1291 1292 if err := task.Kill(ctx, syscall.SIGKILL); err != nil { 1293 t.Error(err) 1294 } 1295 1296 // Give the shim time to reap the init process and kill the orphans 1297 select { 1298 case <-statusC: 1299 case <-time.After(100 * time.Millisecond): 1300 } 1301 1302 b, err := exec.Command("ps", "ax").CombinedOutput() 1303 if err != nil { 1304 t.Fatal(err) 1305 } 1306 1307 if strings.Contains(string(b), "sleep 42") { 1308 t.Fatalf("killing init didn't kill all its children:\n%v", string(b)) 1309 } 1310 1311 if _, err := task.Delete(ctx, WithProcessKill); err != nil { 1312 t.Error(err) 1313 } 1314 } 1315 1316 func TestContainerKillInitPidHost(t *testing.T) { 1317 initContainerAndCheckChildrenDieOnKill(t, oci.WithHostNamespace(specs.PIDNamespace)) 1318 } 1319 1320 func TestContainerKillInitKillsChildWhenNotHostPid(t *testing.T) { 1321 initContainerAndCheckChildrenDieOnKill(t) 1322 } 1323 1324 func TestUserNamespaces(t *testing.T) { 1325 t.Parallel() 1326 t.Run("WritableRootFS", func(t *testing.T) { testUserNamespaces(t, false) }) 1327 // see #1373 and runc#1572 1328 t.Run("ReadonlyRootFS", func(t *testing.T) { testUserNamespaces(t, true) }) 1329 } 1330 1331 func checkUserNS(t *testing.T) { 1332 cmd := exec.Command("true") 1333 cmd.SysProcAttr = &syscall.SysProcAttr{ 1334 Cloneflags: syscall.CLONE_NEWUSER, 1335 } 1336 1337 if err := cmd.Run(); err != nil { 1338 t.Skip("User namespaces are unavailable") 1339 } 1340 } 1341 1342 func testUserNamespaces(t *testing.T, readonlyRootFS bool) { 1343 checkUserNS(t) 1344 1345 client, err := newClient(t, address) 1346 if err != nil { 1347 t.Fatal(err) 1348 } 1349 defer client.Close() 1350 1351 var ( 1352 image Image 1353 ctx, cancel = testContext(t) 1354 id = strings.Replace(t.Name(), "/", "-", -1) 1355 ) 1356 defer cancel() 1357 1358 image, err = client.GetImage(ctx, testImage) 1359 if err != nil { 1360 t.Fatal(err) 1361 } 1362 1363 opts := []NewContainerOpts{WithNewSpec(oci.WithImageConfig(image), 1364 withExitStatus(7), 1365 oci.WithUserNamespace(0, 1000, 10000), 1366 )} 1367 if readonlyRootFS { 1368 opts = append([]NewContainerOpts{WithRemappedSnapshotView(id, image, 1000, 1000)}, opts...) 1369 } else { 1370 opts = append([]NewContainerOpts{WithRemappedSnapshot(id, image, 1000, 1000)}, opts...) 1371 } 1372 1373 container, err := client.NewContainer(ctx, id, opts...) 1374 if err != nil { 1375 t.Fatal(err) 1376 } 1377 defer container.Delete(ctx, WithSnapshotCleanup) 1378 1379 var copts interface{} 1380 if CheckRuntime(client.runtime, "io.containerd.runc") { 1381 copts = &options.Options{ 1382 IoUid: 1000, 1383 IoGid: 1000, 1384 } 1385 } else { 1386 copts = &runctypes.CreateOptions{ 1387 IoUid: 1000, 1388 IoGid: 1000, 1389 } 1390 } 1391 1392 task, err := container.NewTask(ctx, cio.NewCreator(cio.WithStdio), func(_ context.Context, client *Client, r *TaskInfo) error { 1393 r.Options = copts 1394 return nil 1395 }) 1396 if err != nil { 1397 t.Fatal(err) 1398 } 1399 defer task.Delete(ctx) 1400 1401 statusC, err := task.Wait(ctx) 1402 if err != nil { 1403 t.Fatal(err) 1404 } 1405 1406 if pid := task.Pid(); pid < 1 { 1407 t.Errorf("invalid task pid %d", pid) 1408 } 1409 if err := task.Start(ctx); err != nil { 1410 t.Error(err) 1411 task.Delete(ctx) 1412 return 1413 } 1414 status := <-statusC 1415 code, _, err := status.Result() 1416 if err != nil { 1417 t.Fatal(err) 1418 } 1419 if code != 7 { 1420 t.Errorf("expected status 7 from wait but received %d", code) 1421 } 1422 deleteStatus, err := task.Delete(ctx) 1423 if err != nil { 1424 t.Fatal(err) 1425 } 1426 if ec := deleteStatus.ExitCode(); ec != 7 { 1427 t.Errorf("expected status 7 from delete but received %d", ec) 1428 } 1429 } 1430 1431 func TestTaskResize(t *testing.T) { 1432 t.Parallel() 1433 1434 client, err := newClient(t, address) 1435 if err != nil { 1436 t.Fatal(err) 1437 } 1438 defer client.Close() 1439 1440 var ( 1441 image Image 1442 ctx, cancel = testContext(t) 1443 id = t.Name() 1444 ) 1445 defer cancel() 1446 1447 image, err = client.GetImage(ctx, testImage) 1448 if err != nil { 1449 t.Fatal(err) 1450 } 1451 container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withExitStatus(7))) 1452 if err != nil { 1453 t.Fatal(err) 1454 } 1455 defer container.Delete(ctx, WithSnapshotCleanup) 1456 1457 task, err := container.NewTask(ctx, empty()) 1458 if err != nil { 1459 t.Fatal(err) 1460 } 1461 defer task.Delete(ctx) 1462 1463 statusC, err := task.Wait(ctx) 1464 if err != nil { 1465 t.Fatal(err) 1466 } 1467 if err := task.Resize(ctx, 32, 32); err != nil { 1468 t.Fatal(err) 1469 } 1470 task.Kill(ctx, syscall.SIGKILL) 1471 <-statusC 1472 } 1473 1474 func TestContainerImage(t *testing.T) { 1475 t.Parallel() 1476 1477 ctx, cancel := testContext(t) 1478 defer cancel() 1479 id := t.Name() 1480 1481 client, err := newClient(t, address) 1482 if err != nil { 1483 t.Fatal(err) 1484 } 1485 defer client.Close() 1486 1487 image, err := client.GetImage(ctx, testImage) 1488 if err != nil { 1489 t.Fatal(err) 1490 } 1491 1492 container, err := client.NewContainer(ctx, id, WithNewSpec(), WithImage(image)) 1493 if err != nil { 1494 t.Fatal(err) 1495 } 1496 defer container.Delete(ctx) 1497 1498 i, err := container.Image(ctx) 1499 if err != nil { 1500 t.Fatal(err) 1501 } 1502 if i.Name() != image.Name() { 1503 t.Fatalf("expected container image name %s but received %s", image.Name(), i.Name()) 1504 } 1505 } 1506 1507 func TestContainerNoImage(t *testing.T) { 1508 t.Parallel() 1509 1510 ctx, cancel := testContext(t) 1511 defer cancel() 1512 id := t.Name() 1513 1514 client, err := newClient(t, address) 1515 if err != nil { 1516 t.Fatal(err) 1517 } 1518 defer client.Close() 1519 1520 container, err := client.NewContainer(ctx, id, WithNewSpec()) 1521 if err != nil { 1522 t.Fatal(err) 1523 } 1524 defer container.Delete(ctx) 1525 1526 _, err = container.Image(ctx) 1527 if err == nil { 1528 t.Fatal("error should not be nil when container is created without an image") 1529 } 1530 if errors.Cause(err) != errdefs.ErrNotFound { 1531 t.Fatalf("expected error to be %s but received %s", errdefs.ErrNotFound, err) 1532 } 1533 } 1534 1535 func TestUIDNoGID(t *testing.T) { 1536 t.Parallel() 1537 1538 ctx, cancel := testContext(t) 1539 defer cancel() 1540 id := t.Name() 1541 1542 client, err := newClient(t, address) 1543 if err != nil { 1544 t.Fatal(err) 1545 } 1546 defer client.Close() 1547 image, err := client.GetImage(ctx, testImage) 1548 if err != nil { 1549 t.Fatal(err) 1550 } 1551 1552 container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithUserID(1000))) 1553 if err != nil { 1554 t.Fatal(err) 1555 } 1556 defer container.Delete(ctx) 1557 1558 spec, err := container.Spec(ctx) 1559 if err != nil { 1560 t.Fatal(err) 1561 } 1562 if uid := spec.Process.User.UID; uid != 1000 { 1563 t.Fatalf("expected uid 1000 but received %d", uid) 1564 } 1565 if gid := spec.Process.User.GID; gid != 0 { 1566 t.Fatalf("expected gid 0 but received %d", gid) 1567 } 1568 } 1569 1570 func TestBindLowPortNonRoot(t *testing.T) { 1571 t.Parallel() 1572 1573 client, err := newClient(t, address) 1574 if err != nil { 1575 t.Fatal(err) 1576 } 1577 defer client.Close() 1578 1579 var ( 1580 image Image 1581 ctx, cancel = testContext(t) 1582 id = t.Name() 1583 ) 1584 defer cancel() 1585 1586 image, err = client.GetImage(ctx, testImage) 1587 if err != nil { 1588 t.Fatal(err) 1589 } 1590 container, err := client.NewContainer(ctx, id, 1591 WithNewSnapshot(id, image), 1592 WithNewSpec(oci.WithImageConfig(image), withProcessArgs("nc", "-l", "-p", "80"), oci.WithUIDGID(1000, 1000)), 1593 ) 1594 if err != nil { 1595 t.Fatal(err) 1596 } 1597 defer container.Delete(ctx, WithSnapshotCleanup) 1598 1599 task, err := container.NewTask(ctx, empty()) 1600 if err != nil { 1601 t.Fatal(err) 1602 } 1603 defer task.Delete(ctx) 1604 1605 statusC, err := task.Wait(ctx) 1606 if err != nil { 1607 t.Fatal(err) 1608 } 1609 1610 if err := task.Start(ctx); err != nil { 1611 t.Fatal(err) 1612 } 1613 status := <-statusC 1614 code, _, err := status.Result() 1615 if err != nil { 1616 t.Fatal(err) 1617 } 1618 if code != 1 { 1619 t.Errorf("expected status 1 from wait but received %d", code) 1620 } 1621 if _, err := task.Delete(ctx); err != nil { 1622 t.Fatal(err) 1623 } 1624 } 1625 1626 func TestBindLowPortNonOpt(t *testing.T) { 1627 t.Parallel() 1628 1629 client, err := newClient(t, address) 1630 if err != nil { 1631 t.Fatal(err) 1632 } 1633 defer client.Close() 1634 1635 var ( 1636 image Image 1637 ctx, cancel = testContext(t) 1638 id = t.Name() 1639 ) 1640 defer cancel() 1641 1642 image, err = client.GetImage(ctx, testImage) 1643 if err != nil { 1644 t.Fatal(err) 1645 } 1646 container, err := client.NewContainer(ctx, id, 1647 WithNewSnapshot(id, image), 1648 WithNewSpec(oci.WithImageConfig(image), withProcessArgs("nc", "-l", "-p", "80"), oci.WithUIDGID(1000, 1000), oci.WithAmbientCapabilities([]string{"CAP_NET_BIND_SERVICE"})), 1649 ) 1650 if err != nil { 1651 t.Fatal(err) 1652 } 1653 defer container.Delete(ctx, WithSnapshotCleanup) 1654 1655 task, err := container.NewTask(ctx, empty()) 1656 if err != nil { 1657 t.Fatal(err) 1658 } 1659 defer task.Delete(ctx) 1660 1661 statusC, err := task.Wait(ctx) 1662 if err != nil { 1663 t.Fatal(err) 1664 } 1665 1666 if err := task.Start(ctx); err != nil { 1667 t.Fatal(err) 1668 } 1669 go func() { 1670 time.Sleep(2 * time.Second) 1671 task.Kill(ctx, unix.SIGTERM) 1672 }() 1673 status := <-statusC 1674 code, _, err := status.Result() 1675 if err != nil { 1676 t.Fatal(err) 1677 } 1678 // 128 + sigterm 1679 if code != 143 { 1680 t.Errorf("expected status 143 from wait but received %d", code) 1681 } 1682 if _, err := task.Delete(ctx); err != nil { 1683 t.Fatal(err) 1684 } 1685 } 1686 1687 func TestContainerNoSTDIN(t *testing.T) { 1688 t.Parallel() 1689 1690 client, err := newClient(t, address) 1691 if err != nil { 1692 t.Fatal(err) 1693 } 1694 defer client.Close() 1695 1696 var ( 1697 image Image 1698 ctx, cancel = testContext(t) 1699 id = t.Name() 1700 ) 1701 defer cancel() 1702 1703 image, err = client.GetImage(ctx, testImage) 1704 if err != nil { 1705 t.Fatal(err) 1706 } 1707 container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withExitStatus(0))) 1708 if err != nil { 1709 t.Fatal(err) 1710 } 1711 defer container.Delete(ctx, WithSnapshotCleanup) 1712 1713 task, err := container.NewTask(ctx, cio.NewCreator(cio.WithStreams(nil, ioutil.Discard, ioutil.Discard))) 1714 if err != nil { 1715 t.Fatal(err) 1716 } 1717 defer task.Delete(ctx) 1718 1719 statusC, err := task.Wait(ctx) 1720 if err != nil { 1721 t.Fatal(err) 1722 } 1723 if err := task.Start(ctx); err != nil { 1724 t.Fatal(err) 1725 } 1726 status := <-statusC 1727 code, _, err := status.Result() 1728 if err != nil { 1729 t.Fatal(err) 1730 } 1731 if code != 0 { 1732 t.Errorf("expected status 0 from wait but received %d", code) 1733 } 1734 } 1735 1736 func TestShimOOMScore(t *testing.T) { 1737 containerdPid := ctrd.cmd.Process.Pid 1738 containerdScore, err := sys.GetOOMScoreAdj(containerdPid) 1739 if err != nil { 1740 t.Fatal(err) 1741 } 1742 1743 client, err := newClient(t, address) 1744 if err != nil { 1745 t.Fatal(err) 1746 } 1747 defer client.Close() 1748 1749 var ( 1750 image Image 1751 ctx, cancel = testContext(t) 1752 id = t.Name() 1753 ) 1754 defer cancel() 1755 1756 path := "/containerd/oomshim" 1757 cg, err := cgroups.New(cgroups.V1, cgroups.StaticPath(path), &specs.LinuxResources{}) 1758 if err != nil { 1759 t.Fatal(err) 1760 } 1761 defer cg.Delete() 1762 1763 image, err = client.GetImage(ctx, testImage) 1764 if err != nil { 1765 t.Fatal(err) 1766 } 1767 1768 container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "30"))) 1769 if err != nil { 1770 t.Fatal(err) 1771 } 1772 defer container.Delete(ctx, WithSnapshotCleanup) 1773 1774 task, err := container.NewTask(ctx, empty(), WithShimCgroup(path)) 1775 if err != nil { 1776 t.Fatal(err) 1777 } 1778 defer task.Delete(ctx) 1779 1780 statusC, err := task.Wait(ctx) 1781 if err != nil { 1782 t.Fatal(err) 1783 } 1784 1785 processes, err := cg.Processes(cgroups.Devices, false) 1786 if err != nil { 1787 t.Fatal(err) 1788 } 1789 expectedScore := containerdScore + 1 1790 // find the shim's pid 1791 for _, p := range processes { 1792 score, err := sys.GetOOMScoreAdj(p.Pid) 1793 if err != nil { 1794 t.Fatal(err) 1795 } 1796 if score != expectedScore { 1797 t.Errorf("expected score %d but got %d for shim process", expectedScore, score) 1798 } 1799 } 1800 1801 if err := task.Kill(ctx, unix.SIGKILL); err != nil { 1802 t.Fatal(err) 1803 } 1804 1805 <-statusC 1806 }