diff --git a/api/types/events/events.go b/api/types/events/events.go index 5f5f540346..e292565b6c 100644 --- a/api/types/events/events.go +++ b/api/types/events/events.go @@ -19,6 +19,8 @@ const ( NodeEventType = "node" // SecretEventType is the event type that secrets generate SecretEventType = "secret" + // ConfigEventType is the event type that configs generate + ConfigEventType = "config" ) // Actor describes something that generates events, diff --git a/daemon/cluster/noderunner.go b/daemon/cluster/noderunner.go index a1eda066b2..b970e7b217 100644 --- a/daemon/cluster/noderunner.go +++ b/daemon/cluster/noderunner.go @@ -202,6 +202,10 @@ func (n *nodeRunner) watchClusterEvents(ctx context.Context, conn *grpc.ClientCo Kind: "secret", Action: swarmapi.WatchActionKindCreate | swarmapi.WatchActionKindUpdate | swarmapi.WatchActionKindRemove, }, + { + Kind: "config", + Action: swarmapi.WatchActionKindCreate | swarmapi.WatchActionKindUpdate | swarmapi.WatchActionKindRemove, + }, }, IncludeOldObject: true, }) diff --git a/daemon/events.go b/daemon/events.go index f5d188cf0b..7ae851802e 100644 --- a/daemon/events.go +++ b/daemon/events.go @@ -175,6 +175,8 @@ func (daemon *Daemon) generateClusterEvent(msg *swarmapi.WatchMessage) { daemon.logNetworkEvent(event.Action, v.Network, event.OldObject.GetNetwork()) case *swarmapi.Object_Secret: daemon.logSecretEvent(event.Action, v.Secret, event.OldObject.GetSecret()) + case *swarmapi.Object_Config: + daemon.logConfigEvent(event.Action, v.Config, event.OldObject.GetConfig()) default: logrus.Warnf("unrecognized event: %v", event) } @@ -197,6 +199,14 @@ func (daemon *Daemon) logSecretEvent(action swarmapi.WatchActionKind, secret *sw daemon.logClusterEvent(action, secret.ID, "secret", attributes, eventTime) } +func (daemon *Daemon) logConfigEvent(action swarmapi.WatchActionKind, config *swarmapi.Config, oldConfig *swarmapi.Config) { + attributes := map[string]string{ + "name": config.Spec.Annotations.Name, + } + eventTime := eventTimestamp(config.Meta, action) + daemon.logClusterEvent(action, config.ID, "config", attributes, eventTime) +} + func (daemon *Daemon) logNodeEvent(action swarmapi.WatchActionKind, node *swarmapi.Node, oldNode *swarmapi.Node) { name := node.Spec.Annotations.Name if name == "" && node.Description != nil { diff --git a/daemon/events/filter.go b/daemon/events/filter.go index 7f1a5fda1c..645f1ca917 100644 --- a/daemon/events/filter.go +++ b/daemon/events/filter.go @@ -94,6 +94,10 @@ func (ef *Filter) matchSecret(ev events.Message) bool { return ef.fuzzyMatchName(ev, events.SecretEventType) } +func (ef *Filter) matchConfig(ev events.Message) bool { + return ef.fuzzyMatchName(ev, events.ConfigEventType) +} + func (ef *Filter) fuzzyMatchName(ev events.Message, eventType string) bool { return ef.filter.FuzzyMatch(eventType, ev.Actor.ID) || ef.filter.FuzzyMatch(eventType, ev.Actor.Attributes["name"]) diff --git a/integration-cli/docker_cli_swarm_test.go b/integration-cli/docker_cli_swarm_test.go index c5625b4f8c..a0bb7a2283 100644 --- a/integration-cli/docker_cli_swarm_test.go +++ b/integration-cli/docker_cli_swarm_test.go @@ -2208,3 +2208,23 @@ func (s *DockerSwarmSuite) TestSwarmClusterEventsSecret(c *check.C) { // filtered by secret waitForEvent(c, d, t1, "-f type=secret", "secret remove "+id, defaultRetryCount) } + +func (s *DockerSwarmSuite) TestSwarmClusterEventsConfig(c *check.C) { + d := s.AddDaemon(c, true, true) + + testName := "test_config" + id := d.CreateConfig(c, swarm.ConfigSpec{ + Annotations: swarm.Annotations{ + Name: testName, + }, + Data: []byte("TESTINGDATA"), + }) + c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("configs: %s", id)) + + waitForEvent(c, d, "0", "-f scope=swarm", "config create "+id, defaultRetryCount) + + t1 := daemonUnixTime(c) + d.DeleteConfig(c, id) + // filtered by config + waitForEvent(c, d, t1, "-f type=config", "config remove "+id, defaultRetryCount) +}