From 62014aaf9abeb4256cb66e7ae06bfdf5a77d1140 Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Sun, 8 May 2016 16:15:33 -0700 Subject: [PATCH] Add filter for events emitted by docker daemon This fix tries to cover the issue raised in #22463 by adding filter for events emitted by docker daemon so that user could utilize filter to receive events of interest. Documentations have been updated for this fix. Additional tests have been added to cover the changes in this fix. This fix fixes #22463. Signed-off-by: Yong Tang --- daemon/daemon.go | 2 + daemon/events.go | 3 + daemon/events/filter.go | 5 ++ docs/reference/api/docker_remote_api.md | 3 +- docs/reference/api/docker_remote_api_v1.24.md | 3 +- docs/reference/commandline/events.md | 3 +- .../docker_cli_events_unix_test.go | 61 ++++++++++++++++++- 7 files changed, 74 insertions(+), 6 deletions(-) diff --git a/daemon/daemon.go b/daemon/daemon.go index a187486c5d..fb568aa13a 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -1393,6 +1393,8 @@ func (daemon *Daemon) Reload(config *Config) error { } else { attributes["labels"] = "[]" } + attributes["max-concurrent-downloads"] = fmt.Sprintf("%d", *daemon.configStore.MaxConcurrentDownloads) + attributes["max-concurrent-uploads"] = fmt.Sprintf("%d", *daemon.configStore.MaxConcurrentUploads) daemon.LogDaemonEventWithAttributes("reload", attributes) return nil diff --git a/daemon/events.go b/daemon/events.go index 4cec9c1e0d..7fb8cd29ca 100644 --- a/daemon/events.go +++ b/daemon/events.go @@ -83,6 +83,9 @@ func (daemon *Daemon) LogNetworkEventWithAttributes(nw libnetwork.Network, actio // LogDaemonEventWithAttributes generates an event related to the daemon itself with specific given attributes. func (daemon *Daemon) LogDaemonEventWithAttributes(action string, attributes map[string]string) { if daemon.EventsService != nil { + if info, err := daemon.SystemInfo(); err == nil && info.Name != "" { + attributes["name"] = info.Name + } actor := events.Actor{ ID: daemon.ID, Attributes: attributes, diff --git a/daemon/events/filter.go b/daemon/events/filter.go index 8936e371d2..b38c034c9f 100644 --- a/daemon/events/filter.go +++ b/daemon/events/filter.go @@ -20,6 +20,7 @@ func NewFilter(filter filters.Args) *Filter { func (ef *Filter) Include(ev events.Message) bool { return ef.filter.ExactMatch("event", ev.Action) && ef.filter.ExactMatch("type", ev.Type) && + ef.matchDaemon(ev) && ef.matchContainer(ev) && ef.matchVolume(ev) && ef.matchNetwork(ev) && @@ -34,6 +35,10 @@ func (ef *Filter) matchLabels(attributes map[string]string) bool { return ef.filter.MatchKVList("label", attributes) } +func (ef *Filter) matchDaemon(ev events.Message) bool { + return ef.fuzzyMatchName(ev, events.DaemonEventType) +} + func (ef *Filter) matchContainer(ev events.Message) bool { return ef.fuzzyMatchName(ev, events.ContainerEventType) } diff --git a/docs/reference/api/docker_remote_api.md b/docs/reference/api/docker_remote_api.md index 89430d9903..626485effa 100644 --- a/docs/reference/api/docker_remote_api.md +++ b/docs/reference/api/docker_remote_api.md @@ -119,7 +119,8 @@ This section lists each version from latest to oldest. Each listing includes a * `POST /containers/create` now returns a HTTP 400 "bad parameter" message if no command is specified (instead of a HTTP 500 "server error") * `GET /images/search` now takes a `filters` query parameter. -* `GET /events` now supports daemon events of `reload`. +* `GET /events` now supports a `reload` event that is emitted when the daemon configuration is reloaded. +* `GET /events` now supports filtering by daemon name or ID. ### v1.23 API changes diff --git a/docs/reference/api/docker_remote_api_v1.24.md b/docs/reference/api/docker_remote_api_v1.24.md index 55dcd5184b..b7d67d0f29 100644 --- a/docs/reference/api/docker_remote_api_v1.24.md +++ b/docs/reference/api/docker_remote_api_v1.24.md @@ -2593,9 +2593,10 @@ Query Parameters: - `event=`; -- event to filter - `image=`; -- image to filter - `label=`; -- image and container label to filter - - `type=`; -- either `container` or `image` or `volume` or `network` + - `type=`; -- either `container` or `image` or `volume` or `network` or `daemon` - `volume=`; -- volume to filter - `network=`; -- network to filter + - `daemon=`; -- daemon name or id to filter Status Codes: diff --git a/docs/reference/commandline/events.md b/docs/reference/commandline/events.md index 5a7b85f3cb..a958a3a1ed 100644 --- a/docs/reference/commandline/events.md +++ b/docs/reference/commandline/events.md @@ -72,9 +72,10 @@ The currently supported filters are: * event (`event=`) * image (`image=`) * label (`label=` or `label==`) -* type (`type=`) +* type (`type=`) * volume (`volume=`) * network (`network=`) +* daemon (`daemon=`) ## Examples diff --git a/integration-cli/docker_cli_events_unix_test.go b/integration-cli/docker_cli_events_unix_test.go index 435e1a18d7..49c7533a4b 100644 --- a/integration-cli/docker_cli_events_unix_test.go +++ b/integration-cli/docker_cli_events_unix_test.go @@ -386,17 +386,19 @@ func (s *DockerDaemonSuite) TestDaemonEvents(c *check.C) { out, err := s.d.Cmd("info") c.Assert(err, checker.IsNil) daemonID := "" + daemonName := "" for _, line := range strings.Split(out, "\n") { if strings.HasPrefix(line, "ID: ") { daemonID = strings.TrimPrefix(line, "ID: ") - break + } else if strings.HasPrefix(line, "Name: ") { + daemonName = strings.TrimPrefix(line, "Name: ") } } c.Assert(daemonID, checker.Not(checker.Equals), "") configFile, err = os.Create(configFilePath) c.Assert(err, checker.IsNil) - daemonConfig = `{"labels":["bar=foo"]}` + daemonConfig = `{"max-concurrent-downloads":1,"labels":["bar=foo"]}` fmt.Fprintf(configFile, "%s", daemonConfig) configFile.Close() @@ -406,5 +408,58 @@ func (s *DockerDaemonSuite) TestDaemonEvents(c *check.C) { out, err = s.d.Cmd("events", "--since=0", "--until", daemonUnixTime(c)) c.Assert(err, checker.IsNil) - c.Assert(out, checker.Contains, fmt.Sprintf("daemon reload %s (cluster-advertise=, cluster-store=, cluster-store-opts={}, debug=true, labels=[\"bar=foo\"])", daemonID)) + c.Assert(out, checker.Contains, fmt.Sprintf("daemon reload %s (cluster-advertise=, cluster-store=, cluster-store-opts={}, debug=true, labels=[\"bar=foo\"], max-concurrent-downloads=1, max-concurrent-uploads=5, name=%s)", daemonID, daemonName)) +} + +func (s *DockerDaemonSuite) TestDaemonEventsWithFilters(c *check.C) { + testRequires(c, SameHostDaemon, DaemonIsLinux) + + // daemon config file + configFilePath := "test.json" + configFile, err := os.Create(configFilePath) + c.Assert(err, checker.IsNil) + defer os.Remove(configFilePath) + + daemonConfig := `{"labels":["foo=bar"]}` + fmt.Fprintf(configFile, "%s", daemonConfig) + configFile.Close() + c.Assert(s.d.Start(fmt.Sprintf("--config-file=%s", configFilePath)), check.IsNil) + + // Get daemon ID + out, err := s.d.Cmd("info") + c.Assert(err, checker.IsNil) + daemonID := "" + daemonName := "" + for _, line := range strings.Split(out, "\n") { + if strings.HasPrefix(line, "ID: ") { + daemonID = strings.TrimPrefix(line, "ID: ") + } else if strings.HasPrefix(line, "Name: ") { + daemonName = strings.TrimPrefix(line, "Name: ") + } + } + c.Assert(daemonID, checker.Not(checker.Equals), "") + + syscall.Kill(s.d.cmd.Process.Pid, syscall.SIGHUP) + + time.Sleep(3 * time.Second) + + out, err = s.d.Cmd("events", "--since=0", "--until", daemonUnixTime(c), "--filter", fmt.Sprintf("daemon=%s", daemonID)) + c.Assert(err, checker.IsNil) + c.Assert(out, checker.Contains, fmt.Sprintf("daemon reload %s", daemonID)) + + out, err = s.d.Cmd("events", "--since=0", "--until", daemonUnixTime(c), "--filter", fmt.Sprintf("daemon=%s", daemonName)) + c.Assert(err, checker.IsNil) + c.Assert(out, checker.Contains, fmt.Sprintf("daemon reload %s", daemonID)) + + out, err = s.d.Cmd("events", "--since=0", "--until", daemonUnixTime(c), "--filter", "daemon=foo") + c.Assert(err, checker.IsNil) + c.Assert(out, checker.Not(checker.Contains), fmt.Sprintf("daemon reload %s", daemonID)) + + out, err = s.d.Cmd("events", "--since=0", "--until", daemonUnixTime(c), "--filter", "type=daemon") + c.Assert(err, checker.IsNil) + c.Assert(out, checker.Contains, fmt.Sprintf("daemon reload %s", daemonID)) + + out, err = s.d.Cmd("events", "--since=0", "--until", daemonUnixTime(c), "--filter", "type=container") + c.Assert(err, checker.IsNil) + c.Assert(out, checker.Not(checker.Contains), fmt.Sprintf("daemon reload %s", daemonID)) }