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