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  }