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