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  }