github.com/guilhermebr/docker@v1.4.2-0.20150428121140-67da055cebca/integration-cli/docker_cli_events_test.go (about) 1 package main 2 3 import ( 4 "bufio" 5 "fmt" 6 "os/exec" 7 "regexp" 8 "strconv" 9 "strings" 10 "sync" 11 "time" 12 13 "github.com/go-check/check" 14 ) 15 16 func (s *DockerSuite) TestEventsUntag(c *check.C) { 17 image := "busybox" 18 dockerCmd(c, "tag", image, "utest:tag1") 19 dockerCmd(c, "tag", image, "utest:tag2") 20 dockerCmd(c, "rmi", "utest:tag1") 21 dockerCmd(c, "rmi", "utest:tag2") 22 eventsCmd := exec.Command(dockerBinary, "events", "--since=1") 23 out, exitCode, _, err := runCommandWithOutputForDuration(eventsCmd, time.Duration(time.Millisecond*200)) 24 if exitCode != 0 || err != nil { 25 c.Fatalf("Failed to get events - exit code %d: %s", exitCode, err) 26 } 27 events := strings.Split(out, "\n") 28 nEvents := len(events) 29 // The last element after the split above will be an empty string, so we 30 // get the two elements before the last, which are the untags we're 31 // looking for. 32 for _, v := range events[nEvents-3 : nEvents-1] { 33 if !strings.Contains(v, "untag") { 34 c.Fatalf("event should be untag, not %#v", v) 35 } 36 } 37 } 38 39 func (s *DockerSuite) TestEventsContainerFailStartDie(c *check.C) { 40 41 out, _ := dockerCmd(c, "images", "-q") 42 image := strings.Split(out, "\n")[0] 43 eventsCmd := exec.Command(dockerBinary, "run", "--name", "testeventdie", image, "blerg") 44 _, _, err := runCommandWithOutput(eventsCmd) 45 if err == nil { 46 c.Fatalf("Container run with command blerg should have failed, but it did not") 47 } 48 49 eventsCmd = exec.Command(dockerBinary, "events", "--since=0", fmt.Sprintf("--until=%d", daemonTime(c).Unix())) 50 out, _, _ = runCommandWithOutput(eventsCmd) 51 events := strings.Split(out, "\n") 52 if len(events) <= 1 { 53 c.Fatalf("Missing expected event") 54 } 55 56 startEvent := strings.Fields(events[len(events)-3]) 57 dieEvent := strings.Fields(events[len(events)-2]) 58 59 if startEvent[len(startEvent)-1] != "start" { 60 c.Fatalf("event should be start, not %#v", startEvent) 61 } 62 if dieEvent[len(dieEvent)-1] != "die" { 63 c.Fatalf("event should be die, not %#v", dieEvent) 64 } 65 66 } 67 68 func (s *DockerSuite) TestEventsLimit(c *check.C) { 69 70 var waitGroup sync.WaitGroup 71 errChan := make(chan error, 17) 72 73 args := []string{"run", "--rm", "busybox", "true"} 74 for i := 0; i < 17; i++ { 75 waitGroup.Add(1) 76 go func() { 77 defer waitGroup.Done() 78 err := exec.Command(dockerBinary, args...).Run() 79 errChan <- err 80 }() 81 } 82 83 waitGroup.Wait() 84 close(errChan) 85 86 for err := range errChan { 87 if err != nil { 88 c.Fatalf("%q failed with error: %v", strings.Join(args, " "), err) 89 } 90 } 91 92 eventsCmd := exec.Command(dockerBinary, "events", "--since=0", fmt.Sprintf("--until=%d", daemonTime(c).Unix())) 93 out, _, _ := runCommandWithOutput(eventsCmd) 94 events := strings.Split(out, "\n") 95 nEvents := len(events) - 1 96 if nEvents != 64 { 97 c.Fatalf("events should be limited to 64, but received %d", nEvents) 98 } 99 } 100 101 func (s *DockerSuite) TestEventsContainerEvents(c *check.C) { 102 dockerCmd(c, "run", "--rm", "busybox", "true") 103 eventsCmd := exec.Command(dockerBinary, "events", "--since=0", fmt.Sprintf("--until=%d", daemonTime(c).Unix())) 104 out, exitCode, err := runCommandWithOutput(eventsCmd) 105 if exitCode != 0 || err != nil { 106 c.Fatalf("Failed to get events with exit code %d: %s", exitCode, err) 107 } 108 events := strings.Split(out, "\n") 109 events = events[:len(events)-1] 110 if len(events) < 4 { 111 c.Fatalf("Missing expected event") 112 } 113 createEvent := strings.Fields(events[len(events)-4]) 114 startEvent := strings.Fields(events[len(events)-3]) 115 dieEvent := strings.Fields(events[len(events)-2]) 116 destroyEvent := strings.Fields(events[len(events)-1]) 117 if createEvent[len(createEvent)-1] != "create" { 118 c.Fatalf("event should be create, not %#v", createEvent) 119 } 120 if startEvent[len(startEvent)-1] != "start" { 121 c.Fatalf("event should be start, not %#v", startEvent) 122 } 123 if dieEvent[len(dieEvent)-1] != "die" { 124 c.Fatalf("event should be die, not %#v", dieEvent) 125 } 126 if destroyEvent[len(destroyEvent)-1] != "destroy" { 127 c.Fatalf("event should be destroy, not %#v", destroyEvent) 128 } 129 130 } 131 132 func (s *DockerSuite) TestEventsContainerEventsSinceUnixEpoch(c *check.C) { 133 dockerCmd(c, "run", "--rm", "busybox", "true") 134 timeBeginning := time.Unix(0, 0).Format(time.RFC3339Nano) 135 timeBeginning = strings.Replace(timeBeginning, "Z", ".000000000Z", -1) 136 eventsCmd := exec.Command(dockerBinary, "events", fmt.Sprintf("--since='%s'", timeBeginning), 137 fmt.Sprintf("--until=%d", daemonTime(c).Unix())) 138 out, exitCode, err := runCommandWithOutput(eventsCmd) 139 if exitCode != 0 || err != nil { 140 c.Fatalf("Failed to get events with exit code %d: %s", exitCode, err) 141 } 142 events := strings.Split(out, "\n") 143 events = events[:len(events)-1] 144 if len(events) < 4 { 145 c.Fatalf("Missing expected event") 146 } 147 createEvent := strings.Fields(events[len(events)-4]) 148 startEvent := strings.Fields(events[len(events)-3]) 149 dieEvent := strings.Fields(events[len(events)-2]) 150 destroyEvent := strings.Fields(events[len(events)-1]) 151 if createEvent[len(createEvent)-1] != "create" { 152 c.Fatalf("event should be create, not %#v", createEvent) 153 } 154 if startEvent[len(startEvent)-1] != "start" { 155 c.Fatalf("event should be start, not %#v", startEvent) 156 } 157 if dieEvent[len(dieEvent)-1] != "die" { 158 c.Fatalf("event should be die, not %#v", dieEvent) 159 } 160 if destroyEvent[len(destroyEvent)-1] != "destroy" { 161 c.Fatalf("event should be destroy, not %#v", destroyEvent) 162 } 163 164 } 165 166 func (s *DockerSuite) TestEventsImageUntagDelete(c *check.C) { 167 name := "testimageevents" 168 _, err := buildImage(name, 169 `FROM scratch 170 MAINTAINER "docker"`, 171 true) 172 if err != nil { 173 c.Fatal(err) 174 } 175 if err := deleteImages(name); err != nil { 176 c.Fatal(err) 177 } 178 eventsCmd := exec.Command(dockerBinary, "events", "--since=0", fmt.Sprintf("--until=%d", daemonTime(c).Unix())) 179 out, exitCode, err := runCommandWithOutput(eventsCmd) 180 if exitCode != 0 || err != nil { 181 c.Fatalf("Failed to get events with exit code %d: %s", exitCode, err) 182 } 183 events := strings.Split(out, "\n") 184 185 events = events[:len(events)-1] 186 if len(events) < 2 { 187 c.Fatalf("Missing expected event") 188 } 189 untagEvent := strings.Fields(events[len(events)-2]) 190 deleteEvent := strings.Fields(events[len(events)-1]) 191 if untagEvent[len(untagEvent)-1] != "untag" { 192 c.Fatalf("untag should be untag, not %#v", untagEvent) 193 } 194 if deleteEvent[len(deleteEvent)-1] != "delete" { 195 c.Fatalf("delete should be delete, not %#v", deleteEvent) 196 } 197 } 198 199 func (s *DockerSuite) TestEventsImagePull(c *check.C) { 200 since := daemonTime(c).Unix() 201 testRequires(c, Network) 202 203 pullCmd := exec.Command(dockerBinary, "pull", "hello-world") 204 if out, _, err := runCommandWithOutput(pullCmd); err != nil { 205 c.Fatalf("pulling the hello-world image from has failed: %s, %v", out, err) 206 } 207 208 eventsCmd := exec.Command(dockerBinary, "events", 209 fmt.Sprintf("--since=%d", since), 210 fmt.Sprintf("--until=%d", daemonTime(c).Unix())) 211 out, _, _ := runCommandWithOutput(eventsCmd) 212 213 events := strings.Split(strings.TrimSpace(out), "\n") 214 event := strings.TrimSpace(events[len(events)-1]) 215 216 if !strings.HasSuffix(event, "hello-world:latest: pull") { 217 c.Fatalf("Missing pull event - got:%q", event) 218 } 219 220 } 221 222 func (s *DockerSuite) TestEventsImageImport(c *check.C) { 223 since := daemonTime(c).Unix() 224 225 id := make(chan string) 226 eventImport := make(chan struct{}) 227 eventsCmd := exec.Command(dockerBinary, "events", "--since", strconv.FormatInt(since, 10)) 228 stdout, err := eventsCmd.StdoutPipe() 229 if err != nil { 230 c.Fatal(err) 231 } 232 err = eventsCmd.Start() 233 if err != nil { 234 c.Fatal(err) 235 } 236 defer eventsCmd.Process.Kill() 237 238 go func() { 239 containerID := <-id 240 241 matchImport := regexp.MustCompile(containerID + `: import$`) 242 scanner := bufio.NewScanner(stdout) 243 for scanner.Scan() { 244 if matchImport.MatchString(scanner.Text()) { 245 close(eventImport) 246 } 247 } 248 }() 249 250 runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true") 251 out, _, err := runCommandWithOutput(runCmd) 252 if err != nil { 253 c.Fatal("failed to create a container", out, err) 254 } 255 cleanedContainerID := strings.TrimSpace(out) 256 257 out, _, err = runCommandPipelineWithOutput( 258 exec.Command(dockerBinary, "export", cleanedContainerID), 259 exec.Command(dockerBinary, "import", "-"), 260 ) 261 if err != nil { 262 c.Errorf("import failed with errors: %v, output: %q", err, out) 263 } 264 newContainerID := strings.TrimSpace(out) 265 id <- newContainerID 266 267 select { 268 case <-time.After(5 * time.Second): 269 c.Fatal("failed to observe image import in timely fashion") 270 case <-eventImport: 271 // ignore, done 272 } 273 } 274 275 func (s *DockerSuite) TestEventsFilters(c *check.C) { 276 parseEvents := func(out, match string) { 277 events := strings.Split(out, "\n") 278 events = events[:len(events)-1] 279 for _, event := range events { 280 eventFields := strings.Fields(event) 281 eventName := eventFields[len(eventFields)-1] 282 if ok, err := regexp.MatchString(match, eventName); err != nil || !ok { 283 c.Fatalf("event should match %s, got %#v, err: %v", match, eventFields, err) 284 } 285 } 286 } 287 288 since := daemonTime(c).Unix() 289 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "--rm", "busybox", "true")) 290 if err != nil { 291 c.Fatal(out, err) 292 } 293 out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "run", "--rm", "busybox", "true")) 294 if err != nil { 295 c.Fatal(out, err) 296 } 297 out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "events", fmt.Sprintf("--since=%d", since), fmt.Sprintf("--until=%d", daemonTime(c).Unix()), "--filter", "event=die")) 298 if err != nil { 299 c.Fatalf("Failed to get events: %s", err) 300 } 301 parseEvents(out, "die") 302 303 out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "events", fmt.Sprintf("--since=%d", since), fmt.Sprintf("--until=%d", daemonTime(c).Unix()), "--filter", "event=die", "--filter", "event=start")) 304 if err != nil { 305 c.Fatalf("Failed to get events: %s", err) 306 } 307 parseEvents(out, "((die)|(start))") 308 309 // make sure we at least got 2 start events 310 count := strings.Count(out, "start") 311 if count < 2 { 312 c.Fatalf("should have had 2 start events but had %d, out: %s", count, out) 313 } 314 315 } 316 317 func (s *DockerSuite) TestEventsFilterImageName(c *check.C) { 318 since := daemonTime(c).Unix() 319 320 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "--name", "container_1", "-d", "busybox:latest", "true")) 321 if err != nil { 322 c.Fatal(out, err) 323 } 324 container1 := strings.TrimSpace(out) 325 326 out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "run", "--name", "container_2", "-d", "busybox", "true")) 327 if err != nil { 328 c.Fatal(out, err) 329 } 330 container2 := strings.TrimSpace(out) 331 332 name := "busybox" 333 eventsCmd := exec.Command(dockerBinary, "events", fmt.Sprintf("--since=%d", since), fmt.Sprintf("--until=%d", daemonTime(c).Unix()), "--filter", fmt.Sprintf("image=%s", name)) 334 out, _, err = runCommandWithOutput(eventsCmd) 335 if err != nil { 336 c.Fatalf("Failed to get events, error: %s(%s)", err, out) 337 } 338 events := strings.Split(out, "\n") 339 events = events[:len(events)-1] 340 if len(events) == 0 { 341 c.Fatalf("Expected events but found none for the image busybox:latest") 342 } 343 count1 := 0 344 count2 := 0 345 346 for _, e := range events { 347 if strings.Contains(e, container1) { 348 count1++ 349 } else if strings.Contains(e, container2) { 350 count2++ 351 } 352 } 353 if count1 == 0 || count2 == 0 { 354 c.Fatalf("Expected events from each container but got %d from %s and %d from %s", count1, container1, count2, container2) 355 } 356 357 } 358 359 func (s *DockerSuite) TestEventsFilterContainer(c *check.C) { 360 since := fmt.Sprintf("%d", daemonTime(c).Unix()) 361 nameID := make(map[string]string) 362 363 for _, name := range []string{"container_1", "container_2"} { 364 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "--name", name, "busybox", "true")) 365 if err != nil { 366 c.Fatalf("Error: %v, Output: %s", err, out) 367 } 368 id, err := inspectField(name, "Id") 369 if err != nil { 370 c.Fatal(err) 371 } 372 nameID[name] = id 373 } 374 375 until := fmt.Sprintf("%d", daemonTime(c).Unix()) 376 377 checkEvents := func(id string, events []string) error { 378 if len(events) != 3 { // create, start, die 379 return fmt.Errorf("expected 3 events, got %v", events) 380 } 381 for _, event := range events { 382 e := strings.Fields(event) 383 if len(e) < 3 { 384 return fmt.Errorf("got malformed event: %s", event) 385 } 386 387 // Check the id 388 parsedID := strings.TrimSuffix(e[1], ":") 389 if parsedID != id { 390 return fmt.Errorf("expected event for container id %s: %s - parsed container id: %s", id, event, parsedID) 391 } 392 } 393 return nil 394 } 395 396 for name, ID := range nameID { 397 // filter by names 398 eventsCmd := exec.Command(dockerBinary, "events", "--since", since, "--until", until, "--filter", "container="+name) 399 out, _, err := runCommandWithOutput(eventsCmd) 400 if err != nil { 401 c.Fatal(err) 402 } 403 404 events := strings.Split(strings.TrimSuffix(out, "\n"), "\n") 405 if err := checkEvents(ID, events); err != nil { 406 c.Fatal(err) 407 } 408 409 // filter by ID's 410 eventsCmd = exec.Command(dockerBinary, "events", "--since", since, "--until", until, "--filter", "container="+ID) 411 out, _, err = runCommandWithOutput(eventsCmd) 412 if err != nil { 413 c.Fatal(err) 414 } 415 416 events = strings.Split(strings.TrimSuffix(out, "\n"), "\n") 417 if err := checkEvents(ID, events); err != nil { 418 c.Fatal(err) 419 } 420 } 421 422 } 423 424 func (s *DockerSuite) TestEventsStreaming(c *check.C) { 425 start := daemonTime(c).Unix() 426 427 finish := make(chan struct{}) 428 defer close(finish) 429 id := make(chan string) 430 eventCreate := make(chan struct{}) 431 eventStart := make(chan struct{}) 432 eventDie := make(chan struct{}) 433 eventDestroy := make(chan struct{}) 434 435 go func() { 436 eventsCmd := exec.Command(dockerBinary, "events", "--since", strconv.FormatInt(start, 10)) 437 stdout, err := eventsCmd.StdoutPipe() 438 if err != nil { 439 c.Fatal(err) 440 } 441 err = eventsCmd.Start() 442 if err != nil { 443 c.Fatalf("failed to start 'docker events': %s", err) 444 } 445 446 go func() { 447 <-finish 448 eventsCmd.Process.Kill() 449 }() 450 451 containerID := <-id 452 453 matchCreate := regexp.MustCompile(containerID + `: \(from busybox:latest\) create$`) 454 matchStart := regexp.MustCompile(containerID + `: \(from busybox:latest\) start$`) 455 matchDie := regexp.MustCompile(containerID + `: \(from busybox:latest\) die$`) 456 matchDestroy := regexp.MustCompile(containerID + `: \(from busybox:latest\) destroy$`) 457 458 scanner := bufio.NewScanner(stdout) 459 for scanner.Scan() { 460 switch { 461 case matchCreate.MatchString(scanner.Text()): 462 close(eventCreate) 463 case matchStart.MatchString(scanner.Text()): 464 close(eventStart) 465 case matchDie.MatchString(scanner.Text()): 466 close(eventDie) 467 case matchDestroy.MatchString(scanner.Text()): 468 close(eventDestroy) 469 } 470 } 471 472 err = eventsCmd.Wait() 473 if err != nil && !IsKilled(err) { 474 c.Fatalf("docker events had bad exit status: %s", err) 475 } 476 }() 477 478 runCmd := exec.Command(dockerBinary, "run", "-d", "busybox:latest", "true") 479 out, _, err := runCommandWithOutput(runCmd) 480 if err != nil { 481 c.Fatal(out, err) 482 } 483 cleanedContainerID := strings.TrimSpace(out) 484 id <- cleanedContainerID 485 486 select { 487 case <-time.After(5 * time.Second): 488 c.Fatal("failed to observe container create in timely fashion") 489 case <-eventCreate: 490 // ignore, done 491 } 492 493 select { 494 case <-time.After(5 * time.Second): 495 c.Fatal("failed to observe container start in timely fashion") 496 case <-eventStart: 497 // ignore, done 498 } 499 500 select { 501 case <-time.After(5 * time.Second): 502 c.Fatal("failed to observe container die in timely fashion") 503 case <-eventDie: 504 // ignore, done 505 } 506 507 rmCmd := exec.Command(dockerBinary, "rm", cleanedContainerID) 508 out, _, err = runCommandWithOutput(rmCmd) 509 if err != nil { 510 c.Fatal(out, err) 511 } 512 513 select { 514 case <-time.After(5 * time.Second): 515 c.Fatal("failed to observe container destroy in timely fashion") 516 case <-eventDestroy: 517 // ignore, done 518 } 519 520 }