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)) }