github.com/georgethebeatle/containerd@v0.2.5/integration-test/start_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 383 for i := 0; i < totalCtr; i++ { 384 containerID := fmt.Sprintf("top%d", i) 385 c, err := cs.StartContainer(containerID, bundleName) 386 if err != nil { 387 t.Fatal(err) 388 } 389 390 e := c.GetNextEvent() 391 392 t.Assert(*e, checker.Equals, types.Event{ 393 Type: "start-container", 394 Id: containerID, 395 Status: 0, 396 Pid: "", 397 Timestamp: e.Timestamp, 398 }) 399 } 400 401 // restart daemon gracefully (SIGINT) 402 cs.RestartDaemon(false) 403 404 // check that status is running 405 containers, err := cs.ListRunningContainers() 406 if err != nil { 407 t.Fatal(err) 408 } 409 sortContainers(containers) 410 t.Assert(len(containers), checker.Equals, totalCtr) 411 for i := 0; i < totalCtr; i++ { 412 t.Assert(containers[i].Id, checker.Equals, fmt.Sprintf("top%d", i)) 413 t.Assert(containers[i].Status, checker.Equals, "running") 414 } 415 416 // Now kill daemon (SIGKILL) 417 cs.StopDaemon(true) 418 419 // Sleep a second to allow thevent e timestamp to change since 420 // it's second based 421 <-time.After(3 * time.Second) 422 423 // Kill a couple of containers 424 killedCtr := map[int]bool{4: true, 2: true} 425 426 var f func(*types.Event) 427 deathChans := make([]chan error, len(killedCtr)) 428 deathChansIdx := 0 429 430 for i := range killedCtr { 431 ch := make(chan error, 1) 432 deathChans[deathChansIdx] = ch 433 deathChansIdx++ 434 syscall.Kill(int(containers[i].Pids[0]), syscall.SIGKILL) 435 436 // Filter to be notified of their death 437 containerID := fmt.Sprintf("top%d", i) 438 f = func(event *types.Event) { 439 expectedEvent := types.Event{ 440 Type: "exit", 441 Id: containerID, 442 Status: 137, 443 Pid: "init", 444 } 445 expectedEvent.Timestamp = event.Timestamp 446 if ok := t.Check(*event, checker.Equals, expectedEvent); !ok { 447 ch <- fmt.Errorf("Unexpected event: %#v", *event) 448 } else { 449 ch <- nil 450 } 451 } 452 cs.SetContainerEventFilter(containerID, f) 453 } 454 455 cs.RestartDaemon(true) 456 457 // Ensure we got our events 458 for i := range deathChans { 459 done := false 460 for done == false { 461 select { 462 case err := <-deathChans[i]: 463 t.Assert(err, checker.Equals, nil) 464 done = true 465 case <-time.After(3 * time.Second): 466 t.Fatal("Exit event for container not received after 3 seconds") 467 } 468 } 469 } 470 471 // check that status is running 472 containers, err = cs.ListRunningContainers() 473 if err != nil { 474 t.Fatal(err) 475 } 476 sortContainers(containers) 477 t.Assert(len(containers), checker.Equals, totalCtr-len(killedCtr)) 478 idShift := 0 479 for i := 0; i < totalCtr-len(killedCtr); i++ { 480 if _, ok := killedCtr[i+idShift]; ok { 481 idShift++ 482 } 483 t.Assert(containers[i].Id, checker.Equals, fmt.Sprintf("top%d", i+idShift)) 484 t.Assert(containers[i].Status, checker.Equals, "running") 485 } 486 } 487 488 func swapEnabled() bool { 489 _, err := os.Stat("/sys/fs/cgroup/memory/memory.memsw.limit_in_bytes") 490 return err == nil 491 } 492 493 func (cs *ContainerdSuite) TestSigkillShimReuseName(t *check.C) { 494 bundleName := "busybox-top" 495 if err := CreateBusyboxBundle(bundleName, []string{"top"}); err != nil { 496 t.Fatal(err) 497 } 498 containerID := "top" 499 c, err := cs.StartContainer(containerID, bundleName) 500 if err != nil { 501 t.Fatal(err) 502 } 503 504 // Sigkill the shim 505 exec.Command("pkill", "-9", "containerd-shim").Run() 506 507 // Wait for it to be reaped 508 for _, evt := range []types.Event{ 509 { 510 Type: "start-container", 511 Id: containerID, 512 Status: 0, 513 Pid: "", 514 }, 515 { 516 Type: "exit", 517 Id: containerID, 518 Status: 128 + 9, 519 Pid: "init", 520 }, 521 } { 522 ch := c.GetEventsChannel() 523 select { 524 case e := <-ch: 525 evt.Timestamp = e.Timestamp 526 527 t.Assert(*e, checker.Equals, evt) 528 case <-time.After(2 * time.Second): 529 t.Fatal("Container took more than 2 seconds to terminate") 530 } 531 } 532 533 // Start a new continer with the same name 534 c, err = cs.StartContainer(containerID, bundleName) 535 if err != nil { 536 t.Fatal(err) 537 } 538 }