github.com/sameo/containerd@v0.2.8/integration-test/start_linux_test.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "os" 6 "os/exec" 7 "path/filepath" 8 "syscall" 9 "time" 10 11 "github.com/docker/containerd/api/grpc/types" 12 "github.com/docker/docker/pkg/integration/checker" 13 "github.com/go-check/check" 14 ocs "github.com/opencontainers/runtime-spec/specs-go" 15 "google.golang.org/grpc" 16 ) 17 18 func (cs *ContainerdSuite) TestStartBusyboxLsSlash(t *check.C) { 19 expectedOutput := `bin 20 dev 21 etc 22 home 23 lib 24 lib64 25 linuxrc 26 media 27 mnt 28 opt 29 proc 30 root 31 run 32 sbin 33 sys 34 tmp 35 usr 36 var 37 ` 38 if err := CreateBusyboxBundle("busybox-ls-slash", []string{"ls", "/"}); err != nil { 39 t.Fatal(err) 40 } 41 42 c, err := cs.RunContainer("myls", "busybox-ls-slash") 43 if err != nil { 44 t.Fatal(err) 45 } 46 47 t.Assert(c.io.stdoutBuffer.String(), checker.Equals, expectedOutput) 48 } 49 50 func (cs *ContainerdSuite) TestStartBusyboxNoSuchFile(t *check.C) { 51 expectedOutput := `exec: \"NoSuchFile\": executable file not found in $PATH` 52 53 if err := CreateBusyboxBundle("busybox-no-such-file", []string{"NoSuchFile"}); err != nil { 54 t.Fatal(err) 55 } 56 57 _, err := cs.RunContainer("NoSuchFile", "busybox-no-such-file") 58 t.Assert(grpc.ErrorDesc(err), checker.Contains, expectedOutput) 59 } 60 61 func (cs *ContainerdSuite) TestStartBusyboxTop(t *check.C) { 62 bundleName := "busybox-top" 63 if err := CreateBusyboxBundle(bundleName, []string{"top"}); err != nil { 64 t.Fatal(err) 65 } 66 67 containerID := "start-busybox-top" 68 _, err := cs.StartContainer(containerID, bundleName) 69 t.Assert(err, checker.Equals, nil) 70 71 containers, err := cs.ListRunningContainers() 72 if err != nil { 73 t.Fatal(err) 74 } 75 t.Assert(len(containers), checker.Equals, 1) 76 t.Assert(containers[0].Id, checker.Equals, containerID) 77 t.Assert(containers[0].Status, checker.Equals, "running") 78 t.Assert(containers[0].BundlePath, check.Equals, filepath.Join(cs.cwd, GetBundle(bundleName).Path)) 79 } 80 81 func (cs *ContainerdSuite) TestStartBusyboxLsEvents(t *check.C) { 82 if err := CreateBusyboxBundle("busybox-ls", []string{"ls"}); err != nil { 83 t.Fatal(err) 84 } 85 86 containerID := "ls-events" 87 c, err := cs.StartContainer(containerID, "busybox-ls") 88 if err != nil { 89 t.Fatal(err) 90 } 91 92 for _, evt := range []types.Event{ 93 { 94 Type: "start-container", 95 Id: containerID, 96 Status: 0, 97 Pid: "", 98 }, 99 { 100 Type: "exit", 101 Id: containerID, 102 Status: 0, 103 Pid: "init", 104 }, 105 } { 106 ch := c.GetEventsChannel() 107 select { 108 case e := <-ch: 109 evt.Timestamp = e.Timestamp 110 111 t.Assert(*e, checker.Equals, evt) 112 case <-time.After(2 * time.Second): 113 t.Fatal("Container took more than 2 seconds to terminate") 114 } 115 } 116 } 117 118 func (cs *ContainerdSuite) TestStartBusyboxSleep(t *check.C) { 119 if err := CreateBusyboxBundle("busybox-sleep-5", []string{"sleep", "5"}); err != nil { 120 t.Fatal(err) 121 } 122 123 ch := make(chan interface{}) 124 filter := func(e *types.Event) { 125 if e.Type == "exit" && e.Pid == "init" { 126 ch <- nil 127 } 128 } 129 130 start := time.Now() 131 _, err := cs.StartContainerWithEventFilter("sleep5", "busybox-sleep-5", filter) 132 if err != nil { 133 t.Fatal(err) 134 } 135 136 // We add a generous 20% marge of error 137 select { 138 case <-ch: 139 t.Assert(uint64(time.Now().Sub(start)), checker.LessOrEqualThan, uint64(6*time.Second)) 140 case <-time.After(6 * time.Second): 141 t.Fatal("Container took more than 6 seconds to exit") 142 } 143 } 144 145 func (cs *ContainerdSuite) TestStartBusyboxTopKill(t *check.C) { 146 bundleName := "busybox-top" 147 if err := CreateBusyboxBundle(bundleName, []string{"top"}); err != nil { 148 t.Fatal(err) 149 } 150 151 containerID := "top-kill" 152 c, err := cs.StartContainer(containerID, bundleName) 153 if err != nil { 154 t.Fatal(err) 155 } 156 157 <-time.After(1 * time.Second) 158 159 err = cs.KillContainer(containerID) 160 if err != nil { 161 t.Fatal(err) 162 } 163 164 for _, evt := range []types.Event{ 165 { 166 Type: "start-container", 167 Id: containerID, 168 Status: 0, 169 Pid: "", 170 }, 171 { 172 Type: "exit", 173 Id: containerID, 174 Status: 128 + uint32(syscall.SIGKILL), 175 Pid: "init", 176 }, 177 } { 178 ch := c.GetEventsChannel() 179 select { 180 case e := <-ch: 181 evt.Timestamp = e.Timestamp 182 183 t.Assert(*e, checker.Equals, evt) 184 case <-time.After(2 * time.Second): 185 t.Fatal("Container took more than 2 seconds to terminate") 186 } 187 } 188 } 189 190 func (cs *ContainerdSuite) TestStartBusyboxTopSignalSigterm(t *check.C) { 191 bundleName := "busybox-top" 192 if err := CreateBusyboxBundle(bundleName, []string{"top"}); err != nil { 193 t.Fatal(err) 194 } 195 196 containerID := "top-sigterm" 197 c, err := cs.StartContainer(containerID, bundleName) 198 if err != nil { 199 t.Fatal(err) 200 } 201 202 <-time.After(1 * time.Second) 203 204 err = cs.SignalContainer(containerID, uint32(syscall.SIGTERM)) 205 if err != nil { 206 t.Fatal(err) 207 } 208 209 for _, evt := range []types.Event{ 210 { 211 Type: "start-container", 212 Id: containerID, 213 Status: 0, 214 Pid: "", 215 }, 216 { 217 Type: "exit", 218 Id: containerID, 219 Status: 128 + uint32(syscall.SIGTERM), 220 Pid: "init", 221 }, 222 } { 223 ch := c.GetEventsChannel() 224 select { 225 case e := <-ch: 226 evt.Timestamp = e.Timestamp 227 228 t.Assert(*e, checker.Equals, evt) 229 case <-time.After(2 * time.Second): 230 t.Fatal("Container took more than 2 seconds to terminate") 231 } 232 } 233 } 234 235 func (cs *ContainerdSuite) TestStartBusyboxTrapUSR1(t *check.C) { 236 if err := CreateBusyboxBundle("busybox-trap-usr1", []string{"sh", "-c", "trap 'echo -n booh!' SIGUSR1 ; sleep 60 & wait"}); err != nil { 237 t.Fatal(err) 238 } 239 240 containerID := "trap-usr1" 241 c, err := cs.StartContainer(containerID, "busybox-trap-usr1") 242 if err != nil { 243 t.Fatal(err) 244 } 245 246 <-time.After(1 * time.Second) 247 248 if err := cs.SignalContainer(containerID, uint32(syscall.SIGUSR1)); err != nil { 249 t.Fatal(err) 250 } 251 252 for { 253 e := c.GetNextEvent() 254 if e.Type == "exit" && e.Pid == "init" { 255 break 256 } 257 } 258 259 t.Assert(c.io.stdoutBuffer.String(), checker.Equals, "booh!") 260 } 261 262 func (cs *ContainerdSuite) TestStartBusyboxTopPauseResume(t *check.C) { 263 bundleName := "busybox-top" 264 if err := CreateBusyboxBundle(bundleName, []string{"top"}); err != nil { 265 t.Fatal(err) 266 } 267 268 containerID := "top-pause-resume" 269 c, err := cs.StartContainer(containerID, bundleName) 270 if err != nil { 271 t.Fatal(err) 272 } 273 274 if err := cs.PauseContainer(containerID); err != nil { 275 t.Fatal(err) 276 } 277 278 if err := cs.ResumeContainer(containerID); err != nil { 279 t.Fatal(err) 280 } 281 282 for _, evt := range []types.Event{ 283 { 284 Type: "start-container", 285 Id: containerID, 286 Status: 0, 287 Pid: "", 288 }, 289 { 290 Type: "pause", 291 Id: containerID, 292 Status: 0, 293 Pid: "", 294 }, 295 { 296 Type: "resume", 297 Id: containerID, 298 Status: 0, 299 Pid: "", 300 }, 301 } { 302 ch := c.GetEventsChannel() 303 select { 304 case e := <-ch: 305 evt.Timestamp = e.Timestamp 306 307 t.Assert(*e, checker.Equals, evt) 308 case <-time.After(2 * time.Second): 309 t.Fatal("Container took more than 2 seconds to terminate") 310 } 311 } 312 313 // check that status is running 314 containers, err := cs.ListRunningContainers() 315 if err != nil { 316 t.Fatal(err) 317 } 318 t.Assert(len(containers), checker.Equals, 1) 319 t.Assert(containers[0].Id, checker.Equals, containerID) 320 t.Assert(containers[0].Status, checker.Equals, "running") 321 } 322 323 func (cs *ContainerdSuite) TestOOM(t *check.C) { 324 bundleName := "busybox-sh-512k-memlimit" 325 if err := CreateBundleWithFilter("busybox", bundleName, []string{"sh", "-c", "x=oom-party-time; while true; do x=$x$x$x$x$x$x$x$x$x$x; done"}, func(spec *ocs.Spec) { 326 // Limit to 512k for quick oom 327 var limit uint64 = 8 * 1024 * 1024 328 spec.Linux.Resources.Memory = &ocs.Memory{ 329 Limit: &limit, 330 } 331 if swapEnabled() { 332 spec.Linux.Resources.Memory.Swap = &limit 333 } 334 }); err != nil { 335 t.Fatal(err) 336 } 337 338 containerID := "sh-oom" 339 c, err := cs.StartContainer(containerID, bundleName) 340 if err != nil { 341 t.Fatal(err) 342 } 343 344 for _, evt := range []types.Event{ 345 { 346 Type: "start-container", 347 Id: containerID, 348 Status: 0, 349 Pid: "", 350 }, 351 { 352 Type: "oom", 353 Id: containerID, 354 Status: 0, 355 Pid: "", 356 }, 357 { 358 Type: "exit", 359 Id: containerID, 360 Status: 137, 361 Pid: "init", 362 }, 363 } { 364 ch := c.GetEventsChannel() 365 select { 366 case e := <-ch: 367 evt.Timestamp = e.Timestamp 368 t.Assert(*e, checker.Equals, evt) 369 case <-time.After(60 * time.Second): 370 t.Fatalf("Container took more than 60 seconds to %s", evt.Type) 371 } 372 } 373 } 374 375 func (cs *ContainerdSuite) TestRestart(t *check.C) { 376 bundleName := "busybox-top" 377 if err := CreateBusyboxBundle(bundleName, []string{"top"}); err != nil { 378 t.Fatal(err) 379 } 380 381 totalCtr := 10 382 ctrs := make([]*ContainerProcess, totalCtr) 383 384 for i := 0; i < totalCtr; i++ { 385 containerID := fmt.Sprintf("top%d", i) 386 c, err := cs.StartContainer(containerID, bundleName) 387 if err != nil { 388 t.Fatal(err) 389 } 390 391 e := c.GetNextEvent() 392 393 t.Assert(*e, checker.Equals, types.Event{ 394 Type: "start-container", 395 Id: containerID, 396 Status: 0, 397 Pid: "", 398 Timestamp: e.Timestamp, 399 }) 400 ctrs[i] = c 401 } 402 403 // restart daemon gracefully (SIGINT) 404 cs.RestartDaemon(false) 405 406 // check that status is running 407 containers, err := cs.ListRunningContainers() 408 if err != nil { 409 t.Fatal(err) 410 } 411 sortContainers(containers) 412 t.Assert(len(containers), checker.Equals, totalCtr) 413 for i := 0; i < totalCtr; i++ { 414 t.Assert(containers[i].Id, checker.Equals, fmt.Sprintf("top%d", i)) 415 t.Assert(containers[i].Status, checker.Equals, "running") 416 } 417 418 // Check that we can exec see docker/docker# 419 execTarget := "top1" 420 echop, err := cs.AddProcessToContainer(ctrs[1], "echo", "/", []string{"PATH=/bin"}, []string{"sh", "-c", "echo -n Success!"}, 0, 0) 421 t.Assert(err, checker.Equals, nil) 422 for _, evt := range []types.Event{ 423 { 424 Type: "start-process", 425 Id: execTarget, 426 Status: 0, 427 Pid: "echo", 428 }, 429 { 430 Type: "exit", 431 Id: execTarget, 432 Status: 0, 433 Pid: "echo", 434 }, 435 } { 436 ch := ctrs[1].GetEventsChannel() 437 e := <-ch 438 evt.Timestamp = e.Timestamp 439 440 t.Assert(*e, checker.Equals, evt) 441 } 442 t.Assert(echop.io.stdoutBuffer.String(), checker.Equals, "Success!") 443 444 // Now kill daemon (SIGKILL) 445 cs.StopDaemon(true) 446 447 // Sleep a second to allow the timestamp to change since 448 // it's second based 449 <-time.After(3 * time.Second) 450 451 // Kill a couple of containers 452 killedCtr := map[int]bool{4: true, 2: true} 453 454 var f func(*types.Event) 455 deathChans := make([]chan error, len(killedCtr)) 456 deathChansIdx := 0 457 458 for i := range killedCtr { 459 ch := make(chan error, 1) 460 deathChans[deathChansIdx] = ch 461 deathChansIdx++ 462 syscall.Kill(int(containers[i].Pids[0]), syscall.SIGKILL) 463 464 // Filter to be notified of their death 465 containerID := fmt.Sprintf("top%d", i) 466 f = func(event *types.Event) { 467 expectedEvent := types.Event{ 468 Type: "exit", 469 Id: containerID, 470 Status: 137, 471 Pid: "init", 472 } 473 expectedEvent.Timestamp = event.Timestamp 474 if ok := t.Check(*event, checker.Equals, expectedEvent); !ok { 475 ch <- fmt.Errorf("Unexpected event: %#v", *event) 476 } else { 477 ch <- nil 478 } 479 } 480 cs.SetContainerEventFilter(containerID, f) 481 } 482 483 cs.RestartDaemon(true) 484 485 // Ensure we got our events 486 for i := range deathChans { 487 done := false 488 for done == false { 489 select { 490 case err := <-deathChans[i]: 491 t.Assert(err, checker.Equals, nil) 492 done = true 493 case <-time.After(3 * time.Second): 494 t.Fatal("Exit event for container not received after 3 seconds") 495 } 496 } 497 } 498 499 // check that status is running 500 containers, err = cs.ListRunningContainers() 501 if err != nil { 502 t.Fatal(err) 503 } 504 sortContainers(containers) 505 t.Assert(len(containers), checker.Equals, totalCtr-len(killedCtr)) 506 idShift := 0 507 for i := 0; i < totalCtr-len(killedCtr); i++ { 508 if _, ok := killedCtr[i+idShift]; ok { 509 idShift++ 510 } 511 t.Assert(containers[i].Id, checker.Equals, fmt.Sprintf("top%d", i+idShift)) 512 t.Assert(containers[i].Status, checker.Equals, "running") 513 } 514 } 515 516 func swapEnabled() bool { 517 _, err := os.Stat("/sys/fs/cgroup/memory/memory.memsw.limit_in_bytes") 518 return err == nil 519 } 520 521 func (cs *ContainerdSuite) TestSigkillShimReuseName(t *check.C) { 522 bundleName := "busybox-top" 523 if err := CreateBusyboxBundle(bundleName, []string{"top"}); err != nil { 524 t.Fatal(err) 525 } 526 containerID := "top" 527 c, err := cs.StartContainer(containerID, bundleName) 528 if err != nil { 529 t.Fatal(err) 530 } 531 532 // Sigkill the shim 533 exec.Command("pkill", "-9", "containerd-shim").Run() 534 535 // Wait for it to be reaped 536 for _, evt := range []types.Event{ 537 { 538 Type: "start-container", 539 Id: containerID, 540 Status: 0, 541 Pid: "", 542 }, 543 { 544 Type: "exit", 545 Id: containerID, 546 Status: 128 + 9, 547 Pid: "init", 548 }, 549 } { 550 ch := c.GetEventsChannel() 551 select { 552 case e := <-ch: 553 evt.Timestamp = e.Timestamp 554 555 t.Assert(*e, checker.Equals, evt) 556 case <-time.After(2 * time.Second): 557 t.Fatal("Container took more than 2 seconds to terminate") 558 } 559 } 560 561 // Start a new continer with the same name 562 c, err = cs.StartContainer(containerID, bundleName) 563 if err != nil { 564 t.Fatal(err) 565 } 566 }