Browse code

api/types/events: define "Action" type and consts

Define consts for the Actions we use for events, instead of "ad-hoc" strings.
Having these consts makes it easier to find where specific events are triggered,
makes the events less error-prone, and allows documenting each Action (if needed).

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>

Sebastiaan van Stijn authored on 2023/08/26 22:24:46
Showing 70 changed files
... ...
@@ -104,7 +104,7 @@ func (b *Backend) PruneCache(ctx context.Context, opts types.BuildCachePruneOpti
104 104
 	if err != nil {
105 105
 		return nil, errors.Wrap(err, "failed to prune build cache")
106 106
 	}
107
-	b.eventsService.Log("prune", events.BuilderEventType, events.Actor{
107
+	b.eventsService.Log(events.ActionPrune, events.BuilderEventType, events.Actor{
108 108
 		Attributes: map[string]string{
109 109
 			"reclaimed": strconv.FormatInt(buildCacheSize, 10),
110 110
 		},
... ...
@@ -18,6 +18,86 @@ const (
18 18
 	VolumeEventType    Type = "volume"    // VolumeEventType is the event type that volumes generate.
19 19
 )
20 20
 
21
+// Action is used for event-actions.
22
+type Action string
23
+
24
+const (
25
+	ActionCreate       Action = "create"
26
+	ActionStart        Action = "start"
27
+	ActionRestart      Action = "restart"
28
+	ActionStop         Action = "stop"
29
+	ActionCheckpoint   Action = "checkpoint"
30
+	ActionPause        Action = "pause"
31
+	ActionUnPause      Action = "unpause"
32
+	ActionAttach       Action = "attach"
33
+	ActionDetach       Action = "detach"
34
+	ActionResize       Action = "resize"
35
+	ActionUpdate       Action = "update"
36
+	ActionRename       Action = "rename"
37
+	ActionKill         Action = "kill"
38
+	ActionDie          Action = "die"
39
+	ActionOOM          Action = "oom"
40
+	ActionDestroy      Action = "destroy"
41
+	ActionRemove       Action = "remove"
42
+	ActionCommit       Action = "commit"
43
+	ActionTop          Action = "top"
44
+	ActionCopy         Action = "copy"
45
+	ActionArchivePath  Action = "archive-path"
46
+	ActionExtractToDir Action = "extract-to-dir"
47
+	ActionExport       Action = "export"
48
+	ActionImport       Action = "import"
49
+	ActionSave         Action = "save"
50
+	ActionLoad         Action = "load"
51
+	ActionTag          Action = "tag"
52
+	ActionUnTag        Action = "untag"
53
+	ActionPush         Action = "push"
54
+	ActionPull         Action = "pull"
55
+	ActionPrune        Action = "prune"
56
+	ActionDelete       Action = "delete"
57
+	ActionEnable       Action = "enable"
58
+	ActionDisable      Action = "disable"
59
+	ActionConnect      Action = "connect"
60
+	ActionDisconnect   Action = "disconnect"
61
+	ActionReload       Action = "reload"
62
+	ActionMount        Action = "mount"
63
+	ActionUnmount      Action = "unmount"
64
+
65
+	// ActionExecCreate is the prefix used for exec_create events. These
66
+	// event-actions are commonly followed by a colon and space (": "),
67
+	// and the command that's defined for the exec, for example:
68
+	//
69
+	//	exec_create: /bin/sh -c 'echo hello'
70
+	//
71
+	// This is far from ideal; it's a compromise to allow filtering and
72
+	// to preserve backward-compatibility.
73
+	ActionExecCreate Action = "exec_create"
74
+	// ActionExecStart is the prefix used for exec_create events. These
75
+	// event-actions are commonly followed by a colon and space (": "),
76
+	// and the command that's defined for the exec, for example:
77
+	//
78
+	//	exec_start: /bin/sh -c 'echo hello'
79
+	//
80
+	// This is far from ideal; it's a compromise to allow filtering and
81
+	// to preserve backward-compatibility.
82
+	ActionExecStart  Action = "exec_start"
83
+	ActionExecDie    Action = "exec_die"
84
+	ActionExecDetach Action = "exec_detach"
85
+
86
+	// ActionHealthStatus is the prefix to use for health_status events.
87
+	//
88
+	// Health-status events can either have a pre-defined status, in which
89
+	// case the "health_status" action is followed by a colon, or can be
90
+	// "free-form", in which case they're followed by the output of the
91
+	// health-check output.
92
+	//
93
+	// This is far form ideal, and a compromise to allow filtering, and
94
+	// to preserve backward-compatibility.
95
+	ActionHealthStatus          Action = "health_status"
96
+	ActionHealthStatusRunning   Action = "health_status: running"
97
+	ActionHealthStatusHealthy   Action = "health_status: healthy"
98
+	ActionHealthStatusUnhealthy Action = "health_status: unhealthy"
99
+)
100
+
21 101
 // Actor describes something that generates events,
22 102
 // like a container, or a network, or a volume.
23 103
 // It has a defined name and a set of attributes.
... ...
@@ -37,7 +117,7 @@ type Message struct {
37 37
 	From   string `json:"from,omitempty"`   // Deprecated: use Actor.Attributes["image"] instead.
38 38
 
39 39
 	Type   Type
40
-	Action string
40
+	Action Action
41 41
 	Actor  Actor
42 42
 	// Engine events are local scope. Cluster events are swarm scope.
43 43
 	Scope string `json:"scope,omitempty"`
... ...
@@ -90,17 +90,17 @@ func TestEvents(t *testing.T) {
90 90
 				{
91 91
 					Type:   events.BuilderEventType,
92 92
 					Actor:  events.Actor{ID: "1"},
93
-					Action: "create",
93
+					Action: events.ActionCreate,
94 94
 				},
95 95
 				{
96 96
 					Type:   events.BuilderEventType,
97 97
 					Actor:  events.Actor{ID: "1"},
98
-					Action: "die",
98
+					Action: events.ActionDie,
99 99
 				},
100 100
 				{
101 101
 					Type:   events.BuilderEventType,
102 102
 					Actor:  events.Actor{ID: "1"},
103
-					Action: "create",
103
+					Action: events.ActionCreate,
104 104
 				},
105 105
 			},
106 106
 			expectedEvents: map[string]bool{
... ...
@@ -17,6 +17,7 @@ import (
17 17
 	"github.com/containerd/containerd/cio"
18 18
 	"github.com/containerd/containerd/log"
19 19
 	containertypes "github.com/docker/docker/api/types/container"
20
+	"github.com/docker/docker/api/types/events"
20 21
 	mounttypes "github.com/docker/docker/api/types/mount"
21 22
 	swarmtypes "github.com/docker/docker/api/types/swarm"
22 23
 	"github.com/docker/docker/container/stream"
... ...
@@ -488,26 +489,24 @@ func (container *Container) AddMountPointWithVolume(destination string, vol volu
488 488
 }
489 489
 
490 490
 // UnmountVolumes unmounts all volumes
491
-func (container *Container) UnmountVolumes(volumeEventLog func(name, action string, attributes map[string]string)) error {
492
-	var errors []string
491
+func (container *Container) UnmountVolumes(volumeEventLog func(name string, action events.Action, attributes map[string]string)) error {
492
+	var errs []string
493 493
 	for _, volumeMount := range container.MountPoints {
494 494
 		if volumeMount.Volume == nil {
495 495
 			continue
496 496
 		}
497 497
 
498 498
 		if err := volumeMount.Cleanup(); err != nil {
499
-			errors = append(errors, err.Error())
499
+			errs = append(errs, err.Error())
500 500
 			continue
501 501
 		}
502
-
503
-		attributes := map[string]string{
502
+		volumeEventLog(volumeMount.Volume.Name(), events.ActionUnmount, map[string]string{
504 503
 			"driver":    volumeMount.Volume.DriverName(),
505 504
 			"container": container.ID,
506
-		}
507
-		volumeEventLog(volumeMount.Volume.Name(), "unmount", attributes)
505
+		})
508 506
 	}
509
-	if len(errors) > 0 {
510
-		return fmt.Errorf("error while unmounting volumes for container %s: %s", container.ID, strings.Join(errors, "; "))
507
+	if len(errs) > 0 {
508
+		return fmt.Errorf("error while unmounting volumes for container %s: %s", container.ID, strings.Join(errs, "; "))
511 509
 	}
512 510
 	return nil
513 511
 }
... ...
@@ -12,6 +12,7 @@ import (
12 12
 	"github.com/containerd/continuity/fs"
13 13
 	"github.com/docker/docker/api/types"
14 14
 	containertypes "github.com/docker/docker/api/types/container"
15
+	"github.com/docker/docker/api/types/events"
15 16
 	mounttypes "github.com/docker/docker/api/types/mount"
16 17
 	swarmtypes "github.com/docker/docker/api/types/swarm"
17 18
 	"github.com/docker/docker/pkg/stringid"
... ...
@@ -365,7 +366,7 @@ func (container *Container) UpdateContainer(hostConfig *containertypes.HostConfi
365 365
 // DetachAndUnmount uses a detached mount on all mount destinations, then
366 366
 // unmounts each volume normally.
367 367
 // This is used from daemon/archive for `docker cp`
368
-func (container *Container) DetachAndUnmount(volumeEventLog func(name, action string, attributes map[string]string)) error {
368
+func (container *Container) DetachAndUnmount(volumeEventLog func(name string, action events.Action, attributes map[string]string)) error {
369 369
 	ctx := context.TODO()
370 370
 
371 371
 	networkMounts := container.NetworkMounts()
... ...
@@ -7,6 +7,7 @@ import (
7 7
 
8 8
 	"github.com/docker/docker/api/types"
9 9
 	containertypes "github.com/docker/docker/api/types/container"
10
+	"github.com/docker/docker/api/types/events"
10 11
 	swarmtypes "github.com/docker/docker/api/types/swarm"
11 12
 	"github.com/docker/docker/pkg/system"
12 13
 )
... ...
@@ -126,7 +127,7 @@ func (container *Container) ConfigMounts() []Mount {
126 126
 // DetachAndUnmount unmounts all volumes.
127 127
 // On Windows it only delegates to `UnmountVolumes` since there is nothing to
128 128
 // force unmount.
129
-func (container *Container) DetachAndUnmount(volumeEventLog func(name, action string, attributes map[string]string)) error {
129
+func (container *Container) DetachAndUnmount(volumeEventLog func(name string, action events.Action, attributes map[string]string)) error {
130 130
 	return container.UnmountVolumes(volumeEventLog)
131 131
 }
132 132
 
... ...
@@ -9,6 +9,7 @@ import (
9 9
 	"path/filepath"
10 10
 
11 11
 	"github.com/docker/docker/api/types"
12
+	"github.com/docker/docker/api/types/events"
12 13
 	"github.com/docker/docker/container"
13 14
 	"github.com/docker/docker/errdefs"
14 15
 	"github.com/docker/docker/pkg/archive"
... ...
@@ -85,7 +86,7 @@ func (daemon *Daemon) containerArchivePath(container *container.Container, path
85 85
 		return err
86 86
 	})
87 87
 
88
-	daemon.LogContainerEvent(container, "archive-path")
88
+	daemon.LogContainerEvent(container, events.ActionArchivePath)
89 89
 
90 90
 	return content, stat, nil
91 91
 }
... ...
@@ -155,7 +156,7 @@ func (daemon *Daemon) containerExtractToDir(container *container.Container, path
155 155
 		return err
156 156
 	}
157 157
 
158
-	daemon.LogContainerEvent(container, "extract-to-dir")
158
+	daemon.LogContainerEvent(container, events.ActionExtractToDir)
159 159
 
160 160
 	return nil
161 161
 }
... ...
@@ -205,7 +206,7 @@ func (daemon *Daemon) containerCopy(container *container.Container, resource str
205 205
 		container.Unlock()
206 206
 		return err
207 207
 	})
208
-	daemon.LogContainerEvent(container, "copy")
208
+	daemon.LogContainerEvent(container, events.ActionCopy)
209 209
 	return reader, nil
210 210
 }
211 211
 
... ...
@@ -9,6 +9,7 @@ import (
9 9
 
10 10
 	"github.com/docker/docker/api/types"
11 11
 	containertypes "github.com/docker/docker/api/types/container"
12
+	"github.com/docker/docker/api/types/events"
12 13
 	"github.com/docker/docker/container"
13 14
 	"github.com/docker/docker/errdefs"
14 15
 	"github.com/docker/docker/pkg/archive"
... ...
@@ -136,7 +137,7 @@ func (daemon *Daemon) containerArchivePath(container *container.Container, path
136 136
 		return err
137 137
 	})
138 138
 
139
-	daemon.LogContainerEvent(container, "archive-path")
139
+	daemon.LogContainerEvent(container, events.ActionArchivePath)
140 140
 
141 141
 	return content, stat, nil
142 142
 }
... ...
@@ -254,7 +255,7 @@ func (daemon *Daemon) containerExtractToDir(container *container.Container, path
254 254
 		return err
255 255
 	}
256 256
 
257
-	daemon.LogContainerEvent(container, "extract-to-dir")
257
+	daemon.LogContainerEvent(container, events.ActionExtractToDir)
258 258
 
259 259
 	return nil
260 260
 }
... ...
@@ -328,7 +329,7 @@ func (daemon *Daemon) containerCopy(container *container.Container, resource str
328 328
 		container.Unlock()
329 329
 		return err
330 330
 	})
331
-	daemon.LogContainerEvent(container, "copy")
331
+	daemon.LogContainerEvent(container, events.ActionCopy)
332 332
 	return reader, nil
333 333
 }
334 334
 
... ...
@@ -7,6 +7,7 @@ import (
7 7
 
8 8
 	"github.com/containerd/containerd/log"
9 9
 	"github.com/docker/docker/api/types/backend"
10
+	"github.com/docker/docker/api/types/events"
10 11
 	"github.com/docker/docker/container"
11 12
 	"github.com/docker/docker/container/stream"
12 13
 	"github.com/docker/docker/daemon/logger"
... ...
@@ -146,7 +147,7 @@ func (daemon *Daemon) containerAttach(c *container.Container, cfg *stream.Attach
146 146
 		}
147 147
 	}
148 148
 
149
-	daemon.LogContainerEvent(c, "attach")
149
+	daemon.LogContainerEvent(c, events.ActionAttach)
150 150
 
151 151
 	if !doStream {
152 152
 		return nil
... ...
@@ -179,7 +180,7 @@ func (daemon *Daemon) containerAttach(c *container.Container, cfg *stream.Attach
179 179
 	if err != nil {
180 180
 		var ierr term.EscapeError
181 181
 		if errors.Is(err, context.Canceled) || errors.As(err, &ierr) {
182
-			daemon.LogContainerEvent(c, "detach")
182
+			daemon.LogContainerEvent(c, events.ActionDetach)
183 183
 		} else {
184 184
 			log.G(ctx).Errorf("attach failed with error: %v", err)
185 185
 		}
... ...
@@ -7,6 +7,7 @@ import (
7 7
 	"path/filepath"
8 8
 
9 9
 	"github.com/docker/docker/api/types/checkpoint"
10
+	"github.com/docker/docker/api/types/events"
10 11
 	"github.com/docker/docker/daemon/names"
11 12
 )
12 13
 
... ...
@@ -79,7 +80,7 @@ func (daemon *Daemon) CheckpointCreate(name string, config checkpoint.CreateOpti
79 79
 		return fmt.Errorf("Cannot checkpoint container %s: %s", name, err)
80 80
 	}
81 81
 
82
-	daemon.LogContainerEvent(container, "checkpoint")
82
+	daemon.LogContainerEvent(container, events.ActionCheckpoint)
83 83
 
84 84
 	return nil
85 85
 }
... ...
@@ -254,7 +254,7 @@ func (r *controller) Start(ctx context.Context) error {
254 254
 			}
255 255
 
256 256
 			switch event.Action {
257
-			case "die": // exit on terminal events
257
+			case events.ActionDie: // exit on terminal events
258 258
 				ctnr, err := r.adapter.inspect(ctx)
259 259
 				if err != nil {
260 260
 					return errors.Wrap(err, "die event received")
... ...
@@ -263,18 +263,18 @@ func (r *controller) Start(ctx context.Context) error {
263 263
 				}
264 264
 
265 265
 				return nil
266
-			case "destroy":
266
+			case events.ActionDestroy:
267 267
 				// If we get here, something has gone wrong but we want to exit
268 268
 				// and report anyways.
269 269
 				return ErrContainerDestroyed
270
-			case "health_status: unhealthy":
270
+			case events.ActionHealthStatusUnhealthy:
271 271
 				// in this case, we stop the container and report unhealthy status
272 272
 				if err := r.Shutdown(ctx); err != nil {
273 273
 					return errors.Wrap(err, "unhealthy container shutdown failed")
274 274
 				}
275 275
 				// set health check error, and wait for container to fully exit ("die" event)
276 276
 				healthErr = ErrContainerUnhealthy
277
-			case "health_status: healthy":
277
+			case events.ActionHealthStatusHealthy:
278 278
 				if err := r.adapter.activateServiceBinding(); err != nil {
279 279
 					log.G(ctx).WithError(err).Errorf("failed to activate service binding for container %s after healthy event", r.adapter.container.name())
280 280
 					return err
... ...
@@ -716,7 +716,7 @@ func (r *controller) checkHealth(ctx context.Context) error {
716 716
 			}
717 717
 
718 718
 			switch event.Action {
719
-			case "health_status: unhealthy":
719
+			case events.ActionHealthStatusUnhealthy:
720 720
 				return ErrContainerUnhealthy
721 721
 			}
722 722
 		}
... ...
@@ -8,6 +8,7 @@ import (
8 8
 	"time"
9 9
 
10 10
 	containertypes "github.com/docker/docker/api/types/container"
11
+	eventtypes "github.com/docker/docker/api/types/events"
11 12
 	"github.com/docker/docker/container"
12 13
 	"github.com/docker/docker/daemon"
13 14
 	"github.com/docker/docker/daemon/events"
... ...
@@ -71,7 +72,7 @@ func TestHealthStates(t *testing.T) {
71 71
 
72 72
 	// send an event and expect to get expectedErr
73 73
 	// if expectedErr is nil, shouldn't get any error
74
-	logAndExpect := func(msg string, expectedErr error) {
74
+	logAndExpect := func(msg eventtypes.Action, expectedErr error) {
75 75
 		daemon.LogContainerEvent(c, msg)
76 76
 
77 77
 		timer := time.NewTimer(1 * time.Second)
... ...
@@ -90,10 +91,10 @@ func TestHealthStates(t *testing.T) {
90 90
 	}
91 91
 
92 92
 	// events that are ignored by checkHealth
93
-	logAndExpect("health_status: running", nil)
94
-	logAndExpect("health_status: healthy", nil)
95
-	logAndExpect("die", nil)
93
+	logAndExpect(eventtypes.ActionHealthStatusRunning, nil)
94
+	logAndExpect(eventtypes.ActionHealthStatusHealthy, nil)
95
+	logAndExpect(eventtypes.ActionDie, nil)
96 96
 
97 97
 	// unhealthy event will be caught by checkHealth
98
-	logAndExpect("health_status: unhealthy", ErrContainerUnhealthy)
98
+	logAndExpect(eventtypes.ActionHealthStatusUnhealthy, ErrContainerUnhealthy)
99 99
 }
... ...
@@ -10,6 +10,7 @@ import (
10 10
 	"github.com/docker/distribution/reference"
11 11
 	"github.com/docker/docker/api/types/backend"
12 12
 	containertypes "github.com/docker/docker/api/types/container"
13
+	"github.com/docker/docker/api/types/events"
13 14
 	"github.com/docker/docker/builder/dockerfile"
14 15
 	"github.com/docker/docker/errdefs"
15 16
 	"github.com/pkg/errors"
... ...
@@ -180,7 +181,7 @@ func (daemon *Daemon) CreateImageFromContainer(ctx context.Context, name string,
180 180
 		}
181 181
 		imageRef = reference.FamiliarString(c.Tag)
182 182
 	}
183
-	daemon.LogContainerEventWithAttributes(container, "commit", map[string]string{
183
+	daemon.LogContainerEventWithAttributes(container, events.ActionCommit, map[string]string{
184 184
 		"comment":  c.Comment,
185 185
 		"imageID":  id.String(),
186 186
 		"imageRef": imageRef,
... ...
@@ -12,6 +12,7 @@ import (
12 12
 
13 13
 	"github.com/containerd/containerd/log"
14 14
 	containertypes "github.com/docker/docker/api/types/container"
15
+	"github.com/docker/docker/api/types/events"
15 16
 	networktypes "github.com/docker/docker/api/types/network"
16 17
 	"github.com/docker/docker/container"
17 18
 	"github.com/docker/docker/daemon/config"
... ...
@@ -772,7 +773,7 @@ func (daemon *Daemon) connectToNetwork(cfg *config.Config, container *container.
772 772
 
773 773
 	container.NetworkSettings.Ports = getPortMapInfo(sb)
774 774
 
775
-	daemon.LogNetworkEventWithAttributes(n, "connect", map[string]string{"container": container.ID})
775
+	daemon.LogNetworkEventWithAttributes(n, events.ActionConnect, map[string]string{"container": container.ID})
776 776
 	networkActions.WithValues("connect").UpdateSince(start)
777 777
 	return nil
778 778
 }
... ...
@@ -880,7 +881,7 @@ func (daemon *Daemon) tryDetachContainerFromClusterNetwork(network *libnetwork.N
880 880
 			}
881 881
 		}
882 882
 	}
883
-	daemon.LogNetworkEventWithAttributes(network, "disconnect", map[string]string{
883
+	daemon.LogNetworkEventWithAttributes(network, events.ActionDisconnect, map[string]string{
884 884
 		"container": container.ID,
885 885
 	})
886 886
 }
... ...
@@ -1051,7 +1052,7 @@ func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, netw
1051 1051
 	}
1052 1052
 
1053 1053
 	if n != nil {
1054
-		daemon.LogNetworkEventWithAttributes(n, "disconnect", map[string]string{
1054
+		daemon.LogNetworkEventWithAttributes(n, events.ActionDisconnect, map[string]string{
1055 1055
 			"container": container.ID,
1056 1056
 		})
1057 1057
 	}
... ...
@@ -10,6 +10,7 @@ import (
10 10
 	"github.com/containerd/containerd/log"
11 11
 	"github.com/docker/distribution/reference"
12 12
 	"github.com/docker/docker/api/types"
13
+	"github.com/docker/docker/api/types/events"
13 14
 	"github.com/docker/docker/container"
14 15
 	"github.com/docker/docker/image"
15 16
 	"github.com/docker/docker/pkg/stringid"
... ...
@@ -76,7 +77,7 @@ func (i *ImageService) ImageDelete(ctx context.Context, imageRef string, force,
76 76
 		if err != nil {
77 77
 			return nil, err
78 78
 		}
79
-		i.LogImageEvent(imgID.String(), imgID.String(), "untag")
79
+		i.LogImageEvent(imgID.String(), imgID.String(), events.ActionUnTag)
80 80
 		records := []types.ImageDeleteResponseItem{{Untagged: reference.FamiliarString(reference.TagNameOnly(parsedRef))}}
81 81
 		return records, nil
82 82
 	}
... ...
@@ -107,7 +108,7 @@ func (i *ImageService) ImageDelete(ctx context.Context, imageRef string, force,
107 107
 			return nil, err
108 108
 		}
109 109
 
110
-		i.LogImageEvent(imgID.String(), imgID.String(), "untag")
110
+		i.LogImageEvent(imgID.String(), imgID.String(), events.ActionUnTag)
111 111
 		records := []types.ImageDeleteResponseItem{{Untagged: reference.FamiliarString(reference.TagNameOnly(parsedRef))}}
112 112
 		return records, nil
113 113
 	}
... ...
@@ -159,7 +160,7 @@ func (i *ImageService) deleteAll(ctx context.Context, img images.Image, force, p
159 159
 			return records, err
160 160
 		}
161 161
 	}
162
-	i.LogImageEvent(imgID, imgID, "delete")
162
+	i.LogImageEvent(imgID, imgID, events.ActionDelete)
163 163
 	records = append(records, types.ImageDeleteResponseItem{Deleted: imgID})
164 164
 
165 165
 	for _, parent := range parents {
... ...
@@ -172,7 +173,7 @@ func (i *ImageService) deleteAll(ctx context.Context, img images.Image, force, p
172 172
 			break
173 173
 		}
174 174
 		parentID := parent.img.Target.Digest.String()
175
-		i.LogImageEvent(parentID, parentID, "delete")
175
+		i.LogImageEvent(parentID, parentID, events.ActionDelete)
176 176
 		records = append(records, types.ImageDeleteResponseItem{Deleted: parentID})
177 177
 	}
178 178
 
... ...
@@ -259,7 +260,7 @@ func (i *ImageService) imageDeleteHelper(ctx context.Context, img images.Image,
259 259
 		return err
260 260
 	}
261 261
 
262
-	i.LogImageEvent(imgID.String(), imgID.String(), "untag")
262
+	i.LogImageEvent(imgID.String(), imgID.String(), events.ActionUnTag)
263 263
 	*records = append(*records, types.ImageDeleteResponseItem{Untagged: reference.FamiliarString(untaggedRef)})
264 264
 
265 265
 	return nil
... ...
@@ -8,7 +8,7 @@ import (
8 8
 )
9 9
 
10 10
 // LogImageEvent generates an event related to an image with only the default attributes.
11
-func (i *ImageService) LogImageEvent(imageID, refName, action string) {
11
+func (i *ImageService) LogImageEvent(imageID, refName string, action events.Action) {
12 12
 	ctx := context.TODO()
13 13
 	attributes := map[string]string{}
14 14
 
... ...
@@ -14,6 +14,7 @@ import (
14 14
 	"github.com/containerd/containerd/log"
15 15
 	cplatforms "github.com/containerd/containerd/platforms"
16 16
 	"github.com/docker/distribution/reference"
17
+	"github.com/docker/docker/api/types/events"
17 18
 	"github.com/docker/docker/container"
18 19
 	"github.com/docker/docker/errdefs"
19 20
 	"github.com/docker/docker/pkg/platforms"
... ...
@@ -216,7 +217,7 @@ func (i *ImageService) LoadImage(ctx context.Context, inTar io.ReadCloser, outSt
216 216
 		}
217 217
 
218 218
 		fmt.Fprintf(progress, "%s: %s\n", loadedMsg, name)
219
-		i.LogImageEvent(img.Target.Digest.String(), img.Target.Digest.String(), "load")
219
+		i.LogImageEvent(img.Target.Digest.String(), img.Target.Digest.String(), events.ActionLoad)
220 220
 	}
221 221
 
222 222
 	return nil
... ...
@@ -16,6 +16,7 @@ import (
16 16
 	"github.com/containerd/containerd/platforms"
17 17
 	"github.com/docker/distribution/reference"
18 18
 	"github.com/docker/docker/api/types/container"
19
+	"github.com/docker/docker/api/types/events"
19 20
 	"github.com/docker/docker/builder/dockerfile"
20 21
 	"github.com/docker/docker/errdefs"
21 22
 	"github.com/docker/docker/image"
... ...
@@ -146,7 +147,7 @@ func (i *ImageService) ImportImage(ctx context.Context, ref reference.Named, pla
146 146
 	if err != nil {
147 147
 		logger.WithError(err).Debug("failed to unpack image")
148 148
 	} else {
149
-		i.LogImageEvent(id.String(), id.String(), "import")
149
+		i.LogImageEvent(id.String(), id.String(), events.ActionImport)
150 150
 	}
151 151
 
152 152
 	return id, err
... ...
@@ -7,6 +7,7 @@ import (
7 7
 	containerdimages "github.com/containerd/containerd/images"
8 8
 	"github.com/containerd/containerd/log"
9 9
 	"github.com/docker/distribution/reference"
10
+	"github.com/docker/docker/api/types/events"
10 11
 	"github.com/docker/docker/errdefs"
11 12
 	"github.com/docker/docker/image"
12 13
 	"github.com/pkg/errors"
... ...
@@ -39,7 +40,7 @@ func (i *ImageService) TagImage(ctx context.Context, imageID image.ID, newTag re
39 39
 		// Check if image we would replace already resolves to the same target.
40 40
 		// No need to do anything.
41 41
 		if replacedImg.Target.Digest == target.Digest {
42
-			i.LogImageEvent(imageID.String(), reference.FamiliarString(newTag), "tag")
42
+			i.LogImageEvent(imageID.String(), reference.FamiliarString(newTag), events.ActionTag)
43 43
 			return nil
44 44
 		}
45 45
 
... ...
@@ -60,7 +61,7 @@ func (i *ImageService) TagImage(ctx context.Context, imageID image.ID, newTag re
60 60
 	})
61 61
 	logger.Info("image created")
62 62
 
63
-	defer i.LogImageEvent(imageID.String(), reference.FamiliarString(newTag), "tag")
63
+	defer i.LogImageEvent(imageID.String(), reference.FamiliarString(newTag), events.ActionTag)
64 64
 
65 65
 	// The tag succeeded, check if the source image is dangling
66 66
 	sourceDanglingImg, err := is.Get(context.Background(), danglingImageName(target.Digest))
... ...
@@ -13,6 +13,7 @@ import (
13 13
 	"github.com/containerd/containerd/platforms"
14 14
 	"github.com/docker/docker/api/types"
15 15
 	containertypes "github.com/docker/docker/api/types/container"
16
+	"github.com/docker/docker/api/types/events"
16 17
 	imagetypes "github.com/docker/docker/api/types/image"
17 18
 	networktypes "github.com/docker/docker/api/types/network"
18 19
 	"github.com/docker/docker/container"
... ...
@@ -235,7 +236,7 @@ func (daemon *Daemon) create(ctx context.Context, daemonCfg *config.Config, opts
235 235
 		return nil, err
236 236
 	}
237 237
 	stateCtr.set(ctr.ID, "stopped")
238
-	daemon.LogContainerEvent(ctr, "create")
238
+	daemon.LogContainerEvent(ctr, events.ActionCreate)
239 239
 	return ctr, nil
240 240
 }
241 241
 
... ...
@@ -13,6 +13,7 @@ import (
13 13
 	"github.com/containerd/containerd/log"
14 14
 	"github.com/docker/docker/api/types"
15 15
 	containertypes "github.com/docker/docker/api/types/container"
16
+	"github.com/docker/docker/api/types/events"
16 17
 	"github.com/docker/docker/container"
17 18
 	"github.com/docker/docker/daemon/config"
18 19
 	"github.com/docker/docker/errdefs"
... ...
@@ -182,6 +183,6 @@ func (daemon *Daemon) cleanupContainer(container *container.Container, config ty
182 182
 	container.SetRemoved()
183 183
 	stateCtr.del(container.ID)
184 184
 
185
-	daemon.LogContainerEvent(container, "destroy")
185
+	daemon.LogContainerEvent(container, events.ActionDestroy)
186 186
 	return nil
187 187
 }
... ...
@@ -17,12 +17,12 @@ import (
17 17
 )
18 18
 
19 19
 // LogContainerEvent generates an event related to a container with only the default attributes.
20
-func (daemon *Daemon) LogContainerEvent(container *container.Container, action string) {
20
+func (daemon *Daemon) LogContainerEvent(container *container.Container, action events.Action) {
21 21
 	daemon.LogContainerEventWithAttributes(container, action, map[string]string{})
22 22
 }
23 23
 
24 24
 // LogContainerEventWithAttributes generates an event related to a container with specific given attributes.
25
-func (daemon *Daemon) LogContainerEventWithAttributes(container *container.Container, action string, attributes map[string]string) {
25
+func (daemon *Daemon) LogContainerEventWithAttributes(container *container.Container, action events.Action, attributes map[string]string) {
26 26
 	copyAttributes(attributes, container.Config.Labels)
27 27
 	if container.Config.Image != "" {
28 28
 		attributes["image"] = container.Config.Image
... ...
@@ -35,7 +35,7 @@ func (daemon *Daemon) LogContainerEventWithAttributes(container *container.Conta
35 35
 }
36 36
 
37 37
 // LogPluginEvent generates an event related to a plugin with only the default attributes.
38
-func (daemon *Daemon) LogPluginEvent(pluginID, refName, action string) {
38
+func (daemon *Daemon) LogPluginEvent(pluginID, refName string, action events.Action) {
39 39
 	daemon.EventsService.Log(action, events.PluginEventType, events.Actor{
40 40
 		ID:         pluginID,
41 41
 		Attributes: map[string]string{"name": refName},
... ...
@@ -43,7 +43,7 @@ func (daemon *Daemon) LogPluginEvent(pluginID, refName, action string) {
43 43
 }
44 44
 
45 45
 // LogVolumeEvent generates an event related to a volume.
46
-func (daemon *Daemon) LogVolumeEvent(volumeID, action string, attributes map[string]string) {
46
+func (daemon *Daemon) LogVolumeEvent(volumeID string, action events.Action, attributes map[string]string) {
47 47
 	daemon.EventsService.Log(action, events.VolumeEventType, events.Actor{
48 48
 		ID:         volumeID,
49 49
 		Attributes: attributes,
... ...
@@ -51,12 +51,12 @@ func (daemon *Daemon) LogVolumeEvent(volumeID, action string, attributes map[str
51 51
 }
52 52
 
53 53
 // LogNetworkEvent generates an event related to a network with only the default attributes.
54
-func (daemon *Daemon) LogNetworkEvent(nw *libnetwork.Network, action string) {
54
+func (daemon *Daemon) LogNetworkEvent(nw *libnetwork.Network, action events.Action) {
55 55
 	daemon.LogNetworkEventWithAttributes(nw, action, map[string]string{})
56 56
 }
57 57
 
58 58
 // LogNetworkEventWithAttributes generates an event related to a network with specific given attributes.
59
-func (daemon *Daemon) LogNetworkEventWithAttributes(nw *libnetwork.Network, action string, attributes map[string]string) {
59
+func (daemon *Daemon) LogNetworkEventWithAttributes(nw *libnetwork.Network, action events.Action, attributes map[string]string) {
60 60
 	attributes["name"] = nw.Name()
61 61
 	attributes["type"] = nw.Type()
62 62
 	daemon.EventsService.Log(action, events.NetworkEventType, events.Actor{
... ...
@@ -66,7 +66,7 @@ func (daemon *Daemon) LogNetworkEventWithAttributes(nw *libnetwork.Network, acti
66 66
 }
67 67
 
68 68
 // LogDaemonEventWithAttributes generates an event related to the daemon itself with specific given attributes.
69
-func (daemon *Daemon) LogDaemonEventWithAttributes(action string, attributes map[string]string) {
69
+func (daemon *Daemon) LogDaemonEventWithAttributes(action events.Action, attributes map[string]string) {
70 70
 	if daemon.EventsService != nil {
71 71
 		if name := hostName(); name != "" {
72 72
 			attributes["name"] = name
... ...
@@ -248,10 +248,10 @@ func (daemon *Daemon) logServiceEvent(action swarmapi.WatchActionKind, service *
248 248
 	daemon.logClusterEvent(action, service.ID, events.ServiceEventType, eventTime, attributes)
249 249
 }
250 250
 
251
-var clusterEventAction = map[swarmapi.WatchActionKind]string{
252
-	swarmapi.WatchActionKindCreate: "create",
253
-	swarmapi.WatchActionKindUpdate: "update",
254
-	swarmapi.WatchActionKindRemove: "remove",
251
+var clusterEventAction = map[swarmapi.WatchActionKind]events.Action{
252
+	swarmapi.WatchActionKindCreate: events.ActionCreate,
253
+	swarmapi.WatchActionKindUpdate: events.ActionUpdate,
254
+	swarmapi.WatchActionKindRemove: events.ActionRemove,
255 255
 }
256 256
 
257 257
 func (daemon *Daemon) logClusterEvent(action swarmapi.WatchActionKind, id string, eventType events.Type, eventTime time.Time, attributes map[string]string) {
... ...
@@ -79,7 +79,7 @@ func (e *Events) Evict(l chan interface{}) {
79 79
 }
80 80
 
81 81
 // Log creates a local scope message and publishes it
82
-func (e *Events) Log(action string, eventType eventtypes.Type, actor eventtypes.Actor) {
82
+func (e *Events) Log(action eventtypes.Action, eventType eventtypes.Type, actor eventtypes.Actor) {
83 83
 	now := time.Now().UTC()
84 84
 	jm := eventtypes.Message{
85 85
 		Action:   action,
... ...
@@ -94,11 +94,11 @@ func (e *Events) Log(action string, eventType eventtypes.Type, actor eventtypes.
94 94
 	switch eventType {
95 95
 	case eventtypes.ContainerEventType:
96 96
 		jm.ID = actor.ID
97
-		jm.Status = action
97
+		jm.Status = string(action)
98 98
 		jm.From = actor.Attributes["image"]
99 99
 	case eventtypes.ImageEventType:
100 100
 		jm.ID = actor.ID
101
-		jm.Status = action
101
+		jm.Status = string(action)
102 102
 	}
103 103
 
104 104
 	e.PublishMessage(jm)
... ...
@@ -20,7 +20,7 @@ import (
20 20
 // TODO remove this once we removed the deprecated `ID`, `Status`, and `From` fields.
21 21
 func validateLegacyFields(t *testing.T, msg events.Message) {
22 22
 	t.Helper()
23
-	assert.Check(t, is.Equal(msg.Status, msg.Action), "Legacy Status field does not match Action")
23
+	assert.Check(t, is.Equal(msg.Status, string(msg.Action)), "Legacy Status field does not match Action")
24 24
 	assert.Check(t, is.Equal(msg.ID, msg.Actor.ID), "Legacy ID field does not match Actor.ID")
25 25
 	assert.Check(t, is.Equal(msg.From, msg.Actor.Attributes["image"]), "Legacy From field does not match Actor.Attributes.image")
26 26
 }
... ...
@@ -45,7 +45,7 @@ func TestEventsLog(t *testing.T) {
45 45
 		jmsg, ok := msg.(events.Message)
46 46
 		assert.Assert(t, ok, "unexpected type: %T", msg)
47 47
 		validateLegacyFields(t, jmsg)
48
-		assert.Check(t, is.Equal(jmsg.Action, "test"))
48
+		assert.Check(t, is.Equal(jmsg.Action, events.Action("test")))
49 49
 		assert.Check(t, is.Equal(jmsg.Actor.ID, "cont"))
50 50
 		assert.Check(t, is.Equal(jmsg.Actor.Attributes["image"], "image"))
51 51
 	case <-time.After(1 * time.Second):
... ...
@@ -58,7 +58,7 @@ func TestEventsLog(t *testing.T) {
58 58
 		jmsg, ok := msg.(events.Message)
59 59
 		assert.Assert(t, ok, "unexpected type: %T", msg)
60 60
 		validateLegacyFields(t, jmsg)
61
-		assert.Check(t, is.Equal(jmsg.Action, "test"))
61
+		assert.Check(t, is.Equal(jmsg.Action, events.Action("test")))
62 62
 		assert.Check(t, is.Equal(jmsg.Actor.ID, "cont"))
63 63
 		assert.Check(t, is.Equal(jmsg.Actor.Attributes["image"], "image"))
64 64
 	case <-time.After(1 * time.Second):
... ...
@@ -91,7 +91,7 @@ func TestLogEvents(t *testing.T) {
91 91
 
92 92
 	for i := 0; i < eventsLimit+16; i++ {
93 93
 		num := strconv.Itoa(i)
94
-		e.Log("action_"+num, events.ContainerEventType, events.Actor{
94
+		e.Log(events.Action("action_"+num), events.ContainerEventType, events.Actor{
95 95
 			ID:         "cont_" + num,
96 96
 			Attributes: map[string]string{"image": "image_" + num},
97 97
 		})
... ...
@@ -100,7 +100,7 @@ func TestLogEvents(t *testing.T) {
100 100
 	current, l, _ := e.Subscribe()
101 101
 	for i := 0; i < 10; i++ {
102 102
 		num := strconv.Itoa(i + eventsLimit + 16)
103
-		e.Log("action_"+num, events.ContainerEventType, events.Actor{
103
+		e.Log(events.Action("action_"+num), events.ContainerEventType, events.Actor{
104 104
 			ID:         "cont_" + num,
105 105
 			Attributes: map[string]string{"image": "image_" + num},
106 106
 		})
... ...
@@ -121,16 +121,16 @@ func TestLogEvents(t *testing.T) {
121 121
 
122 122
 	first := current[0]
123 123
 	validateLegacyFields(t, first)
124
-	assert.Check(t, is.Equal(first.Action, "action_16"))
124
+	assert.Check(t, is.Equal(first.Action, events.Action("action_16")))
125 125
 
126 126
 	last := current[len(current)-1]
127
-	assert.Check(t, is.Equal(last.Action, "action_271"))
127
+	assert.Check(t, is.Equal(last.Action, events.Action("action_271")))
128 128
 
129 129
 	firstC := msgs[0]
130
-	assert.Check(t, is.Equal(firstC.Action, "action_272"))
130
+	assert.Check(t, is.Equal(firstC.Action, events.Action("action_272")))
131 131
 
132 132
 	lastC := msgs[len(msgs)-1]
133
-	assert.Check(t, is.Equal(lastC.Action, "action_281"))
133
+	assert.Check(t, is.Equal(lastC.Action, events.Action("action_281")))
134 134
 }
135 135
 
136 136
 // Regression-test for https://github.com/moby/moby/issues/20999
... ...
@@ -38,9 +38,9 @@ func (ef *Filter) matchEvent(ev events.Message) bool {
38 38
 	// #25798 if an event filter contains either health_status, exec_create or exec_start without a colon
39 39
 	// Let's to a FuzzyMatch instead of an ExactMatch.
40 40
 	if ef.filterContains("event", map[string]struct{}{"health_status": {}, "exec_create": {}, "exec_start": {}}) {
41
-		return ef.filter.FuzzyMatch("event", ev.Action)
41
+		return ef.filter.FuzzyMatch("event", string(ev.Action))
42 42
 	}
43
-	return ef.filter.ExactMatch("event", ev.Action)
43
+	return ef.filter.ExactMatch("event", string(ev.Action))
44 44
 }
45 45
 
46 46
 func (ef *Filter) filterContains(field string, values map[string]struct{}) bool {
... ...
@@ -66,7 +66,7 @@ func Scan(text string) (*events.Message, error) {
66 66
 		Time:     t,
67 67
 		TimeNano: time.Unix(t, tn).UnixNano(),
68 68
 		Type:     events.Type(md["eventType"]),
69
-		Action:   md["action"],
69
+		Action:   events.Action(md["action"]),
70 70
 		Actor: events.Actor{
71 71
 			ID:         md["id"],
72 72
 			Attributes: attrs,
... ...
@@ -29,7 +29,7 @@ func TestLogContainerEventCopyLabels(t *testing.T) {
29 29
 	daemon := &Daemon{
30 30
 		EventsService: e,
31 31
 	}
32
-	daemon.LogContainerEvent(ctr, "create")
32
+	daemon.LogContainerEvent(ctr, eventtypes.ActionCreate)
33 33
 
34 34
 	if _, mutated := ctr.Config.Labels["image"]; mutated {
35 35
 		t.Fatalf("Expected to not mutate the container labels, got %q", ctr.Config.Labels)
... ...
@@ -59,7 +59,7 @@ func TestLogContainerEventWithAttributes(t *testing.T) {
59 59
 	daemon := &Daemon{
60 60
 		EventsService: e,
61 61
 	}
62
-	daemon.LogContainerEventWithAttributes(ctr, "create", map[string]string{
62
+	daemon.LogContainerEventWithAttributes(ctr, eventtypes.ActionCreate, map[string]string{
63 63
 		"node": "2",
64 64
 		"foo":  "bar",
65 65
 	})
... ...
@@ -13,6 +13,7 @@ import (
13 13
 	"github.com/containerd/containerd/log"
14 14
 	"github.com/docker/docker/api/types"
15 15
 	containertypes "github.com/docker/docker/api/types/container"
16
+	"github.com/docker/docker/api/types/events"
16 17
 	"github.com/docker/docker/api/types/strslice"
17 18
 	"github.com/docker/docker/container"
18 19
 	"github.com/docker/docker/container/stream"
... ...
@@ -137,7 +138,7 @@ func (daemon *Daemon) ContainerExecCreate(name string, config *types.ExecConfig)
137 137
 	}
138 138
 
139 139
 	daemon.registerExecCommand(cntr, execConfig)
140
-	daemon.LogContainerEventWithAttributes(cntr, "exec_create: "+execConfig.Entrypoint+" "+strings.Join(execConfig.Args, " "), map[string]string{
140
+	daemon.LogContainerEventWithAttributes(cntr, events.Action(string(events.ActionExecCreate)+": "+execConfig.Entrypoint+" "+strings.Join(execConfig.Args, " ")), map[string]string{
141 141
 		"execID": execConfig.ID,
142 142
 	})
143 143
 
... ...
@@ -173,7 +174,7 @@ func (daemon *Daemon) ContainerExecStart(ctx context.Context, name string, optio
173 173
 	ec.Unlock()
174 174
 
175 175
 	log.G(ctx).Debugf("starting exec command %s in container %s", ec.ID, ec.Container.ID)
176
-	daemon.LogContainerEventWithAttributes(ec.Container, "exec_start: "+ec.Entrypoint+" "+strings.Join(ec.Args, " "), map[string]string{
176
+	daemon.LogContainerEventWithAttributes(ec.Container, events.Action(string(events.ActionExecStart)+": "+ec.Entrypoint+" "+strings.Join(ec.Args, " ")), map[string]string{
177 177
 		"execID": ec.ID,
178 178
 	})
179 179
 
... ...
@@ -308,7 +309,7 @@ func (daemon *Daemon) ContainerExecStart(ctx context.Context, name string, optio
308 308
 			if _, ok := err.(term.EscapeError); !ok {
309 309
 				return errdefs.System(errors.Wrap(err, "exec attach failed"))
310 310
 			}
311
-			daemon.LogContainerEventWithAttributes(ec.Container, "exec_detach", map[string]string{
311
+			daemon.LogContainerEventWithAttributes(ec.Container, events.ActionExecDetach, map[string]string{
312 312
 				"execID": ec.ID,
313 313
 			})
314 314
 		}
... ...
@@ -5,6 +5,7 @@ import (
5 5
 	"fmt"
6 6
 	"io"
7 7
 
8
+	"github.com/docker/docker/api/types/events"
8 9
 	"github.com/docker/docker/container"
9 10
 	"github.com/docker/docker/errdefs"
10 11
 	"github.com/docker/docker/pkg/archive"
... ...
@@ -58,6 +59,6 @@ func (daemon *Daemon) containerExport(ctx context.Context, container *container.
58 58
 	if err != nil {
59 59
 		return err
60 60
 	}
61
-	daemon.LogContainerEvent(container, "export")
61
+	daemon.LogContainerEvent(container, events.ActionExport)
62 62
 	return nil
63 63
 }
... ...
@@ -12,6 +12,7 @@ import (
12 12
 	"github.com/containerd/containerd/log"
13 13
 	"github.com/docker/docker/api/types"
14 14
 	containertypes "github.com/docker/docker/api/types/container"
15
+	"github.com/docker/docker/api/types/events"
15 16
 	"github.com/docker/docker/api/types/strslice"
16 17
 	"github.com/docker/docker/container"
17 18
 )
... ...
@@ -87,7 +88,7 @@ func (p *cmdProbe) run(ctx context.Context, d *Daemon, cntr *container.Container
87 87
 	execConfig.Env = container.ReplaceOrAppendEnvValues(cntr.CreateDaemonEnvironment(execConfig.Tty, linkedEnv), execConfig.Env)
88 88
 
89 89
 	d.registerExecCommand(cntr, execConfig)
90
-	d.LogContainerEventWithAttributes(cntr, "exec_create: "+execConfig.Entrypoint+" "+strings.Join(execConfig.Args, " "), map[string]string{
90
+	d.LogContainerEventWithAttributes(cntr, events.Action(string(events.ActionExecCreate)+": "+execConfig.Entrypoint+" "+strings.Join(execConfig.Args, " ")), map[string]string{
91 91
 		"execID": execConfig.ID,
92 92
 	})
93 93
 
... ...
@@ -239,7 +240,7 @@ func handleProbeResult(d *Daemon, c *container.Container, result *types.Healthch
239 239
 
240 240
 	current := h.Status()
241 241
 	if oldStatus != current {
242
-		d.LogContainerEvent(c, "health_status: "+current)
242
+		d.LogContainerEvent(c, events.Action(string(events.ActionHealthStatus)+": "+current))
243 243
 	}
244 244
 }
245 245
 
... ...
@@ -49,7 +49,7 @@ func TestHealthStates(t *testing.T) {
49 49
 	_, l, _ := e.Subscribe()
50 50
 	defer e.Evict(l)
51 51
 
52
-	expect := func(expected string) {
52
+	expect := func(expected eventtypes.Action) {
53 53
 		select {
54 54
 		case event := <-l:
55 55
 			ev := event.(eventtypes.Message)
... ...
@@ -97,13 +97,13 @@ func TestHealthStates(t *testing.T) {
97 97
 	// starting -> failed -> success -> failed
98 98
 
99 99
 	handleResult(c.State.StartedAt.Add(1*time.Second), 1)
100
-	expect("health_status: unhealthy")
100
+	expect(eventtypes.ActionHealthStatusUnhealthy)
101 101
 
102 102
 	handleResult(c.State.StartedAt.Add(2*time.Second), 0)
103
-	expect("health_status: healthy")
103
+	expect(eventtypes.ActionHealthStatusHealthy)
104 104
 
105 105
 	handleResult(c.State.StartedAt.Add(3*time.Second), 1)
106
-	expect("health_status: unhealthy")
106
+	expect(eventtypes.ActionHealthStatusUnhealthy)
107 107
 
108 108
 	// Test retries
109 109
 
... ...
@@ -119,10 +119,10 @@ func TestHealthStates(t *testing.T) {
119 119
 		t.Errorf("Expecting FailingStreak=2, but got %d\n", c.State.Health.FailingStreak)
120 120
 	}
121 121
 	handleResult(c.State.StartedAt.Add(60*time.Second), 1)
122
-	expect("health_status: unhealthy")
122
+	expect(eventtypes.ActionHealthStatusUnhealthy)
123 123
 
124 124
 	handleResult(c.State.StartedAt.Add(80*time.Second), 0)
125
-	expect("health_status: healthy")
125
+	expect(eventtypes.ActionHealthStatusHealthy)
126 126
 	if c.State.Health.FailingStreak != 0 {
127 127
 		t.Errorf("Expecting FailingStreak=0, but got %d\n", c.State.Health.FailingStreak)
128 128
 	}
... ...
@@ -148,7 +148,7 @@ func TestHealthStates(t *testing.T) {
148 148
 		t.Errorf("Expecting FailingStreak=1, but got %d\n", c.State.Health.FailingStreak)
149 149
 	}
150 150
 	handleResult(c.State.StartedAt.Add(80*time.Second), 0)
151
-	expect("health_status: healthy")
151
+	expect(eventtypes.ActionHealthStatusHealthy)
152 152
 	if c.State.Health.FailingStreak != 0 {
153 153
 		t.Errorf("Expecting FailingStreak=0, but got %d\n", c.State.Health.FailingStreak)
154 154
 	}
... ...
@@ -7,6 +7,7 @@ import (
7 7
 	"github.com/docker/distribution/reference"
8 8
 	"github.com/docker/docker/api/types"
9 9
 	"github.com/docker/docker/api/types/backend"
10
+	"github.com/docker/docker/api/types/events"
10 11
 	"github.com/docker/docker/api/types/filters"
11 12
 	imagetype "github.com/docker/docker/api/types/image"
12 13
 	"github.com/docker/docker/api/types/registry"
... ...
@@ -34,7 +35,7 @@ type ImageService interface {
34 34
 	PerformWithBaseFS(ctx context.Context, c *container.Container, fn func(string) error) error
35 35
 	LoadImage(ctx context.Context, inTar io.ReadCloser, outStream io.Writer, quiet bool) error
36 36
 	Images(ctx context.Context, opts types.ImageListOptions) ([]*types.ImageSummary, error)
37
-	LogImageEvent(imageID, refName, action string)
37
+	LogImageEvent(imageID, refName string, action events.Action)
38 38
 	CountImages() int
39 39
 	ImagesPrune(ctx context.Context, pruneFilters filters.Args) (*types.ImagesPruneReport, error)
40 40
 	ImportImage(ctx context.Context, ref reference.Named, platform *ocispec.Platform, msg string, layerReader io.Reader, changes []string) (image.ID, error)
... ...
@@ -8,6 +8,7 @@ import (
8 8
 
9 9
 	"github.com/docker/distribution/reference"
10 10
 	"github.com/docker/docker/api/types"
11
+	"github.com/docker/docker/api/types/events"
11 12
 	imagetypes "github.com/docker/docker/api/types/image"
12 13
 	"github.com/docker/docker/container"
13 14
 	"github.com/docker/docker/errdefs"
... ...
@@ -105,7 +106,7 @@ func (i *ImageService) ImageDelete(ctx context.Context, imageRef string, force,
105 105
 
106 106
 		untaggedRecord := types.ImageDeleteResponseItem{Untagged: reference.FamiliarString(parsedRef)}
107 107
 
108
-		i.LogImageEvent(imgID.String(), imgID.String(), "untag")
108
+		i.LogImageEvent(imgID.String(), imgID.String(), events.ActionUnTag)
109 109
 		records = append(records, untaggedRecord)
110 110
 
111 111
 		repoRefs = i.referenceStore.References(imgID.Digest())
... ...
@@ -167,7 +168,7 @@ func (i *ImageService) ImageDelete(ctx context.Context, imageRef string, force,
167 167
 
168 168
 				untaggedRecord := types.ImageDeleteResponseItem{Untagged: reference.FamiliarString(parsedRef)}
169 169
 
170
-				i.LogImageEvent(imgID.String(), imgID.String(), "untag")
170
+				i.LogImageEvent(imgID.String(), imgID.String(), events.ActionUnTag)
171 171
 				records = append(records, untaggedRecord)
172 172
 			}
173 173
 		}
... ...
@@ -248,7 +249,7 @@ func (i *ImageService) removeAllReferencesToImageID(imgID image.ID, records *[]t
248 248
 		if err != nil {
249 249
 			return err
250 250
 		}
251
-		i.LogImageEvent(imgID.String(), imgID.String(), "untag")
251
+		i.LogImageEvent(imgID.String(), imgID.String(), events.ActionUnTag)
252 252
 		*records = append(*records, types.ImageDeleteResponseItem{
253 253
 			Untagged: reference.FamiliarString(parsedRef),
254 254
 		})
... ...
@@ -325,7 +326,7 @@ func (i *ImageService) imageDeleteHelper(imgID image.ID, records *[]types.ImageD
325 325
 		return err
326 326
 	}
327 327
 
328
-	i.LogImageEvent(imgID.String(), imgID.String(), "delete")
328
+	i.LogImageEvent(imgID.String(), imgID.String(), events.ActionDelete)
329 329
 	*records = append(*records, types.ImageDeleteResponseItem{Deleted: imgID.String()})
330 330
 	for _, removedLayer := range removedLayers {
331 331
 		*records = append(*records, types.ImageDeleteResponseItem{Deleted: removedLayer.ChainID.String()})
... ...
@@ -8,7 +8,7 @@ import (
8 8
 )
9 9
 
10 10
 // LogImageEvent generates an event related to an image with only the default attributes.
11
-func (i *ImageService) LogImageEvent(imageID, refName, action string) {
11
+func (i *ImageService) LogImageEvent(imageID, refName string, action events.Action) {
12 12
 	ctx := context.TODO()
13 13
 	attributes := map[string]string{}
14 14
 
... ...
@@ -9,6 +9,7 @@ import (
9 9
 	"github.com/containerd/containerd/platforms"
10 10
 	"github.com/docker/distribution/reference"
11 11
 	"github.com/docker/docker/api/types/container"
12
+	"github.com/docker/docker/api/types/events"
12 13
 	"github.com/docker/docker/builder/dockerfile"
13 14
 	"github.com/docker/docker/dockerversion"
14 15
 	"github.com/docker/docker/errdefs"
... ...
@@ -85,6 +86,6 @@ func (i *ImageService) ImportImage(ctx context.Context, newRef reference.Named,
85 85
 		}
86 86
 	}
87 87
 
88
-	i.LogImageEvent(id.String(), id.String(), "import")
88
+	i.LogImageEvent(id.String(), id.String(), events.ActionImport)
89 89
 	return id, nil
90 90
 }
... ...
@@ -147,7 +147,7 @@ deleteImagesLoop:
147 147
 	if canceled {
148 148
 		log.G(ctx).Debugf("ImagesPrune operation cancelled: %#v", *rep)
149 149
 	}
150
-	i.eventsService.Log("prune", events.ImageEventType, events.Actor{
150
+	i.eventsService.Log(events.ActionPrune, events.ImageEventType, events.Actor{
151 151
 		Attributes: map[string]string{
152 152
 			"reclaimed": strconv.FormatUint(rep.SpaceReclaimed, 10),
153 153
 		},
... ...
@@ -4,6 +4,7 @@ import (
4 4
 	"context"
5 5
 
6 6
 	"github.com/docker/distribution/reference"
7
+	"github.com/docker/docker/api/types/events"
7 8
 	"github.com/docker/docker/image"
8 9
 )
9 10
 
... ...
@@ -16,6 +17,6 @@ func (i *ImageService) TagImage(ctx context.Context, imageID image.ID, newTag re
16 16
 	if err := i.imageStore.SetLastUpdated(imageID); err != nil {
17 17
 		return err
18 18
 	}
19
-	i.LogImageEvent(imageID.String(), reference.FamiliarString(newTag), "tag")
19
+	i.LogImageEvent(imageID.String(), reference.FamiliarString(newTag), events.ActionTag)
20 20
 	return nil
21 21
 }
... ...
@@ -9,6 +9,7 @@ import (
9 9
 	"time"
10 10
 
11 11
 	"github.com/containerd/containerd/log"
12
+	"github.com/docker/docker/api/types/events"
12 13
 	containerpkg "github.com/docker/docker/container"
13 14
 	"github.com/docker/docker/errdefs"
14 15
 	"github.com/moby/sys/signal"
... ...
@@ -126,7 +127,7 @@ func (daemon *Daemon) killWithSignal(container *containerpkg.Container, stopSign
126 126
 		}
127 127
 	}
128 128
 
129
-	daemon.LogContainerEventWithAttributes(container, "kill", map[string]string{
129
+	daemon.LogContainerEventWithAttributes(container, events.ActionKill, map[string]string{
130 130
 		"signal": strconv.Itoa(int(stopSignal)),
131 131
 	})
132 132
 	return nil
... ...
@@ -7,6 +7,7 @@ import (
7 7
 
8 8
 	"github.com/containerd/containerd/log"
9 9
 	"github.com/docker/docker/api/types"
10
+	"github.com/docker/docker/api/types/events"
10 11
 	"github.com/docker/docker/container"
11 12
 	"github.com/docker/docker/daemon/config"
12 13
 	"github.com/docker/docker/errdefs"
... ...
@@ -110,7 +111,7 @@ func (daemon *Daemon) handleContainerExit(c *container.Container, e *libcontaine
110 110
 	daemon.setStateCounter(c)
111 111
 	checkpointErr := c.CheckpointTo(daemon.containersReplica)
112 112
 
113
-	daemon.LogContainerEventWithAttributes(c, "die", attributes)
113
+	daemon.LogContainerEventWithAttributes(c, events.ActionDie, attributes)
114 114
 
115 115
 	if restart {
116 116
 		go func() {
... ...
@@ -168,7 +169,7 @@ func (daemon *Daemon) ProcessEvent(id string, e libcontainerdtypes.EventType, ei
168 168
 			return err
169 169
 		}
170 170
 
171
-		daemon.LogContainerEvent(c, "oom")
171
+		daemon.LogContainerEvent(c, events.ActionOOM)
172 172
 	case libcontainerdtypes.EventExit:
173 173
 		if ei.ProcessID == ei.ContainerID {
174 174
 			return daemon.handleContainerExit(c, &ei)
... ...
@@ -219,7 +220,7 @@ func (daemon *Daemon) ProcessEvent(id string, e libcontainerdtypes.EventType, ei
219 219
 				}()
220 220
 			}
221 221
 		}
222
-		daemon.LogContainerEventWithAttributes(c, "exec_die", map[string]string{
222
+		daemon.LogContainerEventWithAttributes(c, events.ActionExecDie, map[string]string{
223 223
 			"execID":   ei.ProcessID,
224 224
 			"exitCode": strconv.Itoa(exitCode),
225 225
 		})
... ...
@@ -263,7 +264,7 @@ func (daemon *Daemon) ProcessEvent(id string, e libcontainerdtypes.EventType, ei
263 263
 			if err := c.CheckpointTo(daemon.containersReplica); err != nil {
264 264
 				return err
265 265
 			}
266
-			daemon.LogContainerEvent(c, "start")
266
+			daemon.LogContainerEvent(c, events.ActionStart)
267 267
 		}
268 268
 
269 269
 	case libcontainerdtypes.EventPaused:
... ...
@@ -277,7 +278,7 @@ func (daemon *Daemon) ProcessEvent(id string, e libcontainerdtypes.EventType, ei
277 277
 			if err := c.CheckpointTo(daemon.containersReplica); err != nil {
278 278
 				return err
279 279
 			}
280
-			daemon.LogContainerEvent(c, "pause")
280
+			daemon.LogContainerEvent(c, events.ActionPause)
281 281
 		}
282 282
 	case libcontainerdtypes.EventResumed:
283 283
 		c.Lock()
... ...
@@ -291,7 +292,7 @@ func (daemon *Daemon) ProcessEvent(id string, e libcontainerdtypes.EventType, ei
291 291
 			if err := c.CheckpointTo(daemon.containersReplica); err != nil {
292 292
 				return err
293 293
 			}
294
-			daemon.LogContainerEvent(c, "unpause")
294
+			daemon.LogContainerEvent(c, events.ActionUnPause)
295 295
 		}
296 296
 	}
297 297
 	return nil
... ...
@@ -13,6 +13,7 @@ import (
13 13
 	"github.com/containerd/containerd/log"
14 14
 	"github.com/docker/docker/api/types"
15 15
 	containertypes "github.com/docker/docker/api/types/container"
16
+	"github.com/docker/docker/api/types/events"
16 17
 	"github.com/docker/docker/api/types/filters"
17 18
 	"github.com/docker/docker/api/types/network"
18 19
 	"github.com/docker/docker/container"
... ...
@@ -388,7 +389,7 @@ func (daemon *Daemon) createNetwork(cfg *config.Config, create types.NetworkCrea
388 388
 	if create.IPAM != nil {
389 389
 		daemon.pluginRefCount(create.IPAM.Driver, ipamapi.PluginEndpointType, plugingetter.Acquire)
390 390
 	}
391
-	daemon.LogNetworkEvent(n, "create")
391
+	daemon.LogNetworkEvent(n, events.ActionCreate)
392 392
 
393 393
 	return &types.NetworkCreateResponse{
394 394
 		ID:      n.ID(),
... ...
@@ -555,7 +556,7 @@ func (daemon *Daemon) deleteNetwork(nw *libnetwork.Network, dynamic bool) error
555 555
 		daemon.pluginRefCount(nw.Type(), driverapi.NetworkPluginEndpointType, plugingetter.Release)
556 556
 		ipamType, _, _, _ := nw.IpamConfig()
557 557
 		daemon.pluginRefCount(ipamType, ipamapi.PluginEndpointType, plugingetter.Release)
558
-		daemon.LogNetworkEvent(nw, "destroy")
558
+		daemon.LogNetworkEvent(nw, events.ActionDestroy)
559 559
 	}
560 560
 
561 561
 	return nil
... ...
@@ -5,6 +5,7 @@ import (
5 5
 	"fmt"
6 6
 
7 7
 	"github.com/containerd/containerd/log"
8
+	"github.com/docker/docker/api/types/events"
8 9
 	"github.com/docker/docker/container"
9 10
 )
10 11
 
... ...
@@ -46,7 +47,7 @@ func (daemon *Daemon) containerPause(container *container.Container) error {
46 46
 	container.Paused = true
47 47
 	daemon.setStateCounter(container)
48 48
 	daemon.updateHealthMonitor(container)
49
-	daemon.LogContainerEvent(container, "pause")
49
+	daemon.LogContainerEvent(container, events.ActionPause)
50 50
 
51 51
 	if err := container.CheckpointTo(daemon.containersReplica); err != nil {
52 52
 		log.G(context.TODO()).WithError(err).Warn("could not save container to disk")
... ...
@@ -89,7 +89,7 @@ func (daemon *Daemon) ContainersPrune(ctx context.Context, pruneFilters filters.
89 89
 			rep.ContainersDeleted = append(rep.ContainersDeleted, c.ID)
90 90
 		}
91 91
 	}
92
-	daemon.EventsService.Log("prune", events.ContainerEventType, events.Actor{
92
+	daemon.EventsService.Log(events.ActionPrune, events.ContainerEventType, events.Actor{
93 93
 		Attributes: map[string]string{"reclaimed": strconv.FormatUint(rep.SpaceReclaimed, 10)},
94 94
 	})
95 95
 	return rep, nil
... ...
@@ -216,7 +216,7 @@ func (daemon *Daemon) NetworksPrune(ctx context.Context, pruneFilters filters.Ar
216 216
 		return rep, nil
217 217
 	default:
218 218
 	}
219
-	daemon.EventsService.Log("prune", events.NetworkEventType, events.Actor{
219
+	daemon.EventsService.Log(events.ActionPrune, events.NetworkEventType, events.Actor{
220 220
 		Attributes: map[string]string{"reclaimed": "0"},
221 221
 	})
222 222
 	return rep, nil
... ...
@@ -7,6 +7,7 @@ import (
7 7
 	"strconv"
8 8
 
9 9
 	"github.com/containerd/containerd/log"
10
+	"github.com/docker/docker/api/types/events"
10 11
 	"github.com/hashicorp/go-multierror"
11 12
 	"github.com/mitchellh/copystructure"
12 13
 
... ...
@@ -127,7 +128,7 @@ func (daemon *Daemon) Reload(conf *config.Config) error {
127 127
 	})
128 128
 	log.G(context.TODO()).Infof("Reloaded configuration: %s", jsonString)
129 129
 	daemon.configStore.Store(newCfg)
130
-	daemon.LogDaemonEventWithAttributes("reload", attributes)
130
+	daemon.LogDaemonEventWithAttributes(events.ActionReload, attributes)
131 131
 	return txn.Commit()
132 132
 }
133 133
 
... ...
@@ -5,6 +5,7 @@ import (
5 5
 	"strings"
6 6
 
7 7
 	"github.com/containerd/containerd/log"
8
+	"github.com/docker/docker/api/types/events"
8 9
 	dockercontainer "github.com/docker/docker/container"
9 10
 	"github.com/docker/docker/errdefs"
10 11
 	"github.com/docker/docker/libnetwork"
... ...
@@ -93,7 +94,7 @@ func (daemon *Daemon) ContainerRename(oldName, newName string) error {
93 93
 	}
94 94
 
95 95
 	if !container.Running {
96
-		daemon.LogContainerEventWithAttributes(container, "rename", attributes)
96
+		daemon.LogContainerEventWithAttributes(container, events.ActionRename, attributes)
97 97
 		return nil
98 98
 	}
99 99
 
... ...
@@ -120,6 +121,6 @@ func (daemon *Daemon) ContainerRename(oldName, newName string) error {
120 120
 		}
121 121
 	}
122 122
 
123
-	daemon.LogContainerEventWithAttributes(container, "rename", attributes)
123
+	daemon.LogContainerEventWithAttributes(container, events.ActionRename, attributes)
124 124
 	return nil
125 125
 }
... ...
@@ -6,6 +6,7 @@ import (
6 6
 	"strconv"
7 7
 	"time"
8 8
 
9
+	"github.com/docker/docker/api/types/events"
9 10
 	"github.com/docker/docker/errdefs"
10 11
 )
11 12
 
... ...
@@ -25,7 +26,7 @@ func (daemon *Daemon) ContainerResize(name string, height, width int) error {
25 25
 	}
26 26
 
27 27
 	if err = tsk.Resize(context.Background(), uint32(width), uint32(height)); err == nil {
28
-		daemon.LogContainerEventWithAttributes(container, "resize", map[string]string{
28
+		daemon.LogContainerEventWithAttributes(container, events.ActionResize, map[string]string{
29 29
 			"height": strconv.Itoa(height),
30 30
 			"width":  strconv.Itoa(width),
31 31
 		})
... ...
@@ -5,6 +5,7 @@ import (
5 5
 	"fmt"
6 6
 
7 7
 	containertypes "github.com/docker/docker/api/types/container"
8
+	"github.com/docker/docker/api/types/events"
8 9
 	"github.com/docker/docker/container"
9 10
 )
10 11
 
... ...
@@ -64,6 +65,6 @@ func (daemon *Daemon) containerRestart(ctx context.Context, daemonCfg *configSto
64 64
 		return err
65 65
 	}
66 66
 
67
-	daemon.LogContainerEvent(container, "restart")
67
+	daemon.LogContainerEvent(container, events.ActionRestart)
68 68
 	return nil
69 69
 }
... ...
@@ -8,6 +8,7 @@ import (
8 8
 	"github.com/containerd/containerd/log"
9 9
 	"github.com/docker/docker/api/types"
10 10
 	containertypes "github.com/docker/docker/api/types/container"
11
+	"github.com/docker/docker/api/types/events"
11 12
 	"github.com/docker/docker/container"
12 13
 	"github.com/docker/docker/errdefs"
13 14
 	"github.com/docker/docker/libcontainerd"
... ...
@@ -222,7 +223,7 @@ func (daemon *Daemon) containerStart(ctx context.Context, daemonCfg *configStore
222 222
 			Errorf("failed to store container")
223 223
 	}
224 224
 
225
-	daemon.LogContainerEvent(container, "start")
225
+	daemon.LogContainerEvent(container, events.ActionStart)
226 226
 	containerActions.WithValues("start").UpdateSince(start)
227 227
 
228 228
 	return nil
... ...
@@ -6,6 +6,7 @@ import (
6 6
 
7 7
 	"github.com/containerd/containerd/log"
8 8
 	containertypes "github.com/docker/docker/api/types/container"
9
+	"github.com/docker/docker/api/types/events"
9 10
 	"github.com/docker/docker/container"
10 11
 	"github.com/docker/docker/errdefs"
11 12
 	"github.com/moby/sys/signal"
... ...
@@ -73,7 +74,7 @@ func (daemon *Daemon) containerStop(_ context.Context, ctr *container.Container,
73 73
 	}
74 74
 	defer func() {
75 75
 		if retErr == nil {
76
-			daemon.LogContainerEvent(ctr, "stop")
76
+			daemon.LogContainerEvent(ctr, events.ActionStop)
77 77
 		}
78 78
 	}()
79 79
 
... ...
@@ -12,6 +12,7 @@ import (
12 12
 	"strings"
13 13
 
14 14
 	"github.com/docker/docker/api/types/container"
15
+	"github.com/docker/docker/api/types/events"
15 16
 	"github.com/docker/docker/errdefs"
16 17
 	libcontainerdtypes "github.com/docker/docker/libcontainerd/types"
17 18
 	"github.com/pkg/errors"
... ...
@@ -198,6 +199,6 @@ func (daemon *Daemon) ContainerTop(name string, psArgs string) (*container.Conta
198 198
 	if err != nil {
199 199
 		return nil, err
200 200
 	}
201
-	daemon.LogContainerEvent(ctr, "top")
201
+	daemon.LogContainerEvent(ctr, events.ActionTop)
202 202
 	return procList, nil
203 203
 }
... ...
@@ -5,6 +5,7 @@ import (
5 5
 	"fmt"
6 6
 
7 7
 	"github.com/containerd/containerd/log"
8
+	"github.com/docker/docker/api/types/events"
8 9
 	"github.com/docker/docker/container"
9 10
 )
10 11
 
... ...
@@ -38,7 +39,7 @@ func (daemon *Daemon) containerUnpause(ctr *container.Container) error {
38 38
 	ctr.Paused = false
39 39
 	daemon.setStateCounter(ctr)
40 40
 	daemon.updateHealthMonitor(ctr)
41
-	daemon.LogContainerEvent(ctr, "unpause")
41
+	daemon.LogContainerEvent(ctr, events.ActionUnPause)
42 42
 
43 43
 	if err := ctr.CheckpointTo(daemon.containersReplica); err != nil {
44 44
 		log.G(context.TODO()).WithError(err).Warn("could not save container to disk")
... ...
@@ -5,6 +5,7 @@ import (
5 5
 	"fmt"
6 6
 
7 7
 	"github.com/docker/docker/api/types/container"
8
+	"github.com/docker/docker/api/types/events"
8 9
 	"github.com/docker/docker/errdefs"
9 10
 	"github.com/pkg/errors"
10 11
 )
... ...
@@ -75,7 +76,7 @@ func (daemon *Daemon) update(name string, hostConfig *container.HostConfig) erro
75 75
 		ctr.UpdateMonitor(hostConfig.RestartPolicy)
76 76
 	}
77 77
 
78
-	defer daemon.LogContainerEvent(ctr, "update")
78
+	defer daemon.LogContainerEvent(ctr, events.ActionUpdate)
79 79
 
80 80
 	// If container is not running, update hostConfig struct is enough,
81 81
 	// resources will be updated when the container is started again.
... ...
@@ -9,6 +9,7 @@ import (
9 9
 	"strconv"
10 10
 	"strings"
11 11
 
12
+	"github.com/docker/docker/api/types/events"
12 13
 	mounttypes "github.com/docker/docker/api/types/mount"
13 14
 	"github.com/docker/docker/container"
14 15
 	volumemounts "github.com/docker/docker/volume/mounts"
... ...
@@ -73,7 +74,7 @@ func (daemon *Daemon) setupMounts(c *container.Container) ([]container.Mount, er
73 73
 				mnt.ReadOnlyForceRecursive = m.Spec.BindOptions.ReadOnlyForceRecursive
74 74
 			}
75 75
 			if m.Volume != nil {
76
-				daemon.LogVolumeEvent(m.Volume.Name(), "mount", map[string]string{
76
+				daemon.LogVolumeEvent(m.Volume.Name(), events.ActionMount, map[string]string{
77 77
 					"driver":      m.Volume.DriverName(),
78 78
 					"container":   c.ID,
79 79
 					"destination": m.Destination,
... ...
@@ -9,6 +9,7 @@ import (
9 9
 	"github.com/docker/distribution"
10 10
 	"github.com/docker/distribution/manifest/schema2"
11 11
 	"github.com/docker/distribution/reference"
12
+	"github.com/docker/docker/api/types/events"
12 13
 	"github.com/docker/docker/api/types/registry"
13 14
 	"github.com/docker/docker/distribution/metadata"
14 15
 	"github.com/docker/docker/distribution/xfer"
... ...
@@ -38,7 +39,7 @@ type Config struct {
38 38
 	// and endpoint lookup.
39 39
 	RegistryService RegistryResolver
40 40
 	// ImageEventLogger notifies events for a given image
41
-	ImageEventLogger func(id, name, action string)
41
+	ImageEventLogger func(id, name string, action events.Action)
42 42
 	// MetadataStore is the storage backend for distribution-specific
43 43
 	// metadata.
44 44
 	MetadataStore metadata.Store
... ...
@@ -7,6 +7,7 @@ import (
7 7
 	"github.com/containerd/containerd/log"
8 8
 	"github.com/docker/distribution/reference"
9 9
 	"github.com/docker/docker/api"
10
+	"github.com/docker/docker/api/types/events"
10 11
 	refstore "github.com/docker/docker/reference"
11 12
 	"github.com/opencontainers/go-digest"
12 13
 	"github.com/pkg/errors"
... ...
@@ -73,7 +74,7 @@ func Pull(ctx context.Context, ref reference.Named, config *ImagePullConfig, loc
73 73
 			return translatePullError(err, ref)
74 74
 		}
75 75
 
76
-		config.ImageEventLogger(reference.FamiliarString(ref), reference.FamiliarName(repoInfo.Name), "pull")
76
+		config.ImageEventLogger(reference.FamiliarString(ref), reference.FamiliarName(repoInfo.Name), events.ActionPull)
77 77
 		return nil
78 78
 	}
79 79
 
... ...
@@ -9,6 +9,7 @@ import (
9 9
 
10 10
 	"github.com/containerd/containerd/log"
11 11
 	"github.com/docker/distribution/reference"
12
+	"github.com/docker/docker/api/types/events"
12 13
 	"github.com/docker/docker/pkg/progress"
13 14
 )
14 15
 
... ...
@@ -77,7 +78,7 @@ func Push(ctx context.Context, ref reference.Named, config *ImagePushConfig) err
77 77
 			return err
78 78
 		}
79 79
 
80
-		config.ImageEventLogger(reference.FamiliarString(ref), reference.FamiliarName(repoInfo.Name), "push")
80
+		config.ImageEventLogger(reference.FamiliarString(ref), reference.FamiliarName(repoInfo.Name), events.ActionPush)
81 81
 		return nil
82 82
 	}
83 83
 
... ...
@@ -14,6 +14,7 @@ import (
14 14
 	"github.com/containerd/containerd/log"
15 15
 	"github.com/docker/distribution"
16 16
 	"github.com/docker/distribution/reference"
17
+	"github.com/docker/docker/api/types/events"
17 18
 	"github.com/docker/docker/image"
18 19
 	v1 "github.com/docker/docker/image/v1"
19 20
 	"github.com/docker/docker/layer"
... ...
@@ -137,7 +138,7 @@ func (l *tarexporter) Load(inTar io.ReadCloser, outStream io.Writer, quiet bool)
137 137
 		}
138 138
 
139 139
 		parentLinks = append(parentLinks, parentLink{imgID, m.Parent})
140
-		l.loggerImgEvent.LogImageEvent(imgID.String(), imgID.String(), "load")
140
+		l.loggerImgEvent.LogImageEvent(imgID.String(), imgID.String(), events.ActionLoad)
141 141
 	}
142 142
 
143 143
 	for _, p := range validatedParentLinks(parentLinks) {
... ...
@@ -12,6 +12,7 @@ import (
12 12
 	"github.com/containerd/containerd/images"
13 13
 	"github.com/docker/distribution"
14 14
 	"github.com/docker/distribution/reference"
15
+	"github.com/docker/docker/api/types/events"
15 16
 	"github.com/docker/docker/image"
16 17
 	v1 "github.com/docker/docker/image/v1"
17 18
 	"github.com/docker/docker/layer"
... ...
@@ -290,7 +291,7 @@ func (s *saveSession) save(outStream io.Writer) error {
290 290
 
291 291
 		parentID, _ := s.is.GetParent(id)
292 292
 		parentLinks = append(parentLinks, parentLink{id, parentID})
293
-		s.tarexporter.loggerImgEvent.LogImageEvent(id.String(), id.String(), "save")
293
+		s.tarexporter.loggerImgEvent.LogImageEvent(id.String(), id.String(), events.ActionSave)
294 294
 	}
295 295
 
296 296
 	for i, p := range validatedParentLinks(parentLinks) {
... ...
@@ -2,6 +2,7 @@ package tarexport // import "github.com/docker/docker/image/tarexport"
2 2
 
3 3
 import (
4 4
 	"github.com/docker/distribution"
5
+	"github.com/docker/docker/api/types/events"
5 6
 	"github.com/docker/docker/image"
6 7
 	"github.com/docker/docker/layer"
7 8
 	refstore "github.com/docker/docker/reference"
... ...
@@ -36,7 +37,7 @@ type tarexporter struct {
36 36
 // LogImageEvent defines interface for event generation related to image tar(load and save) operations
37 37
 type LogImageEvent interface {
38 38
 	// LogImageEvent generates an event related to an image operation
39
-	LogImageEvent(imageID, refName, action string)
39
+	LogImageEvent(imageID, refName string, action events.Action)
40 40
 }
41 41
 
42 42
 // NewTarExporter returns new Exporter for tar packages
... ...
@@ -736,7 +736,7 @@ func (s *DockerCLIEventSuite) TestEventsFormat(c *testing.T) {
736 736
 			break
737 737
 		}
738 738
 		assert.NilError(c, err)
739
-		if ev.Action == "start" {
739
+		if ev.Action == eventtypes.ActionStart {
740 740
 			startCount++
741 741
 		}
742 742
 	}
... ...
@@ -50,7 +50,7 @@ func TestPause(t *testing.T) {
50 50
 		Until:   until,
51 51
 		Filters: filters.NewArgs(filters.Arg(string(events.ContainerEventType), cID)),
52 52
 	})
53
-	assert.Check(t, is.DeepEqual([]string{"pause", "unpause"}, getEventActions(t, messages, errs)))
53
+	assert.Check(t, is.DeepEqual([]events.Action{events.ActionPause, events.ActionUnPause}, getEventActions(t, messages, errs)))
54 54
 }
55 55
 
56 56
 func TestPauseFailsOnWindowsServerContainers(t *testing.T) {
... ...
@@ -87,9 +87,9 @@ func TestPauseStopPausedContainer(t *testing.T) {
87 87
 	poll.WaitOn(t, container.IsStopped(ctx, apiClient, cID), poll.WithDelay(100*time.Millisecond))
88 88
 }
89 89
 
90
-func getEventActions(t *testing.T, messages <-chan events.Message, errs <-chan error) []string {
90
+func getEventActions(t *testing.T, messages <-chan events.Message, errs <-chan error) []events.Action {
91 91
 	t.Helper()
92
-	var actions []string
92
+	var actions []events.Action
93 93
 	for {
94 94
 		select {
95 95
 		case err := <-errs:
... ...
@@ -232,10 +232,10 @@ func TestAuthZPluginAllowEventStream(t *testing.T) {
232 232
 		select {
233 233
 		case event := <-events:
234 234
 			if event.Type == eventtypes.ContainerEventType && event.Actor.ID == cID {
235
-				if event.Action == "create" {
235
+				if event.Action == eventtypes.ActionCreate {
236 236
 					created = true
237 237
 				}
238
-				if event.Action == "start" {
238
+				if event.Action == eventtypes.ActionStart {
239 239
 					started = true
240 240
 				}
241 241
 			}
... ...
@@ -46,7 +46,7 @@ func TestEventsExecDie(t *testing.T) {
46 46
 	msg, errs := client.Events(ctx, types.EventsOptions{
47 47
 		Filters: filters.NewArgs(
48 48
 			filters.Arg("container", cID),
49
-			filters.Arg("event", "exec_die"),
49
+			filters.Arg("event", string(events.ActionExecDie)),
50 50
 		),
51 51
 	})
52 52
 
... ...
@@ -62,7 +62,7 @@ func TestEventsExecDie(t *testing.T) {
62 62
 	case m := <-msg:
63 63
 		assert.Equal(t, m.Type, events.ContainerEventType)
64 64
 		assert.Equal(t, m.Actor.ID, cID)
65
-		assert.Equal(t, m.Action, "exec_die")
65
+		assert.Equal(t, m.Action, events.ActionExecDie)
66 66
 		assert.Equal(t, m.Actor.Attributes["execID"], id.ID)
67 67
 		assert.Equal(t, m.Actor.Attributes["exitCode"], "0")
68 68
 	case err = <-errs:
... ...
@@ -23,6 +23,7 @@ import (
23 23
 	"github.com/docker/distribution/manifest/schema2"
24 24
 	"github.com/docker/distribution/reference"
25 25
 	"github.com/docker/docker/api/types"
26
+	"github.com/docker/docker/api/types/events"
26 27
 	"github.com/docker/docker/api/types/filters"
27 28
 	"github.com/docker/docker/api/types/registry"
28 29
 	"github.com/docker/docker/dockerversion"
... ...
@@ -69,7 +70,7 @@ func (pm *Manager) Disable(refOrID string, config *types.PluginDisableConfig) er
69 69
 		return err
70 70
 	}
71 71
 	pm.publisher.Publish(EventDisable{Plugin: p.PluginObj})
72
-	pm.config.LogPluginEvent(p.GetID(), refOrID, "disable")
72
+	pm.config.LogPluginEvent(p.GetID(), refOrID, events.ActionDisable)
73 73
 	return nil
74 74
 }
75 75
 
... ...
@@ -85,7 +86,7 @@ func (pm *Manager) Enable(refOrID string, config *types.PluginEnableConfig) erro
85 85
 		return err
86 86
 	}
87 87
 	pm.publisher.Publish(EventEnable{Plugin: p.PluginObj})
88
-	pm.config.LogPluginEvent(p.GetID(), refOrID, "enable")
88
+	pm.config.LogPluginEvent(p.GetID(), refOrID, events.ActionEnable)
89 89
 	return nil
90 90
 }
91 91
 
... ...
@@ -239,7 +240,7 @@ func (pm *Manager) Upgrade(ctx context.Context, ref reference.Named, name string
239 239
 	if err := pm.fetch(ctx, ref, authConfig, out, metaHeader, storeFetchMetadata(&md), childrenHandler(pm.blobStore), applyLayer(pm.blobStore, tmpRootFSDir, out)); err != nil {
240 240
 		return err
241 241
 	}
242
-	pm.config.LogPluginEvent(reference.FamiliarString(ref), name, "pull")
242
+	pm.config.LogPluginEvent(reference.FamiliarString(ref), name, events.ActionPull)
243 243
 
244 244
 	if err := validateFetchedMetadata(md); err != nil {
245 245
 		return err
... ...
@@ -285,7 +286,7 @@ func (pm *Manager) Pull(ctx context.Context, ref reference.Named, name string, m
285 285
 	if err := pm.fetch(ctx, ref, authConfig, out, metaHeader, storeFetchMetadata(&md), childrenHandler(pm.blobStore), applyLayer(pm.blobStore, tmpRootFSDir, out)); err != nil {
286 286
 		return err
287 287
 	}
288
-	pm.config.LogPluginEvent(reference.FamiliarString(ref), name, "pull")
288
+	pm.config.LogPluginEvent(reference.FamiliarString(ref), name, events.ActionPull)
289 289
 
290 290
 	if err := validateFetchedMetadata(md); err != nil {
291 291
 		return err
... ...
@@ -599,7 +600,7 @@ func (pm *Manager) Remove(name string, config *types.PluginRmConfig) error {
599 599
 	}
600 600
 
601 601
 	pm.config.Store.Remove(p)
602
-	pm.config.LogPluginEvent(id, name, "remove")
602
+	pm.config.LogPluginEvent(id, name, events.ActionRemove)
603 603
 	pm.publisher.Publish(EventRemove{Plugin: p.PluginObj})
604 604
 	return nil
605 605
 }
... ...
@@ -727,7 +728,7 @@ func (pm *Manager) CreateFromContext(ctx context.Context, tarCtx io.ReadCloser,
727 727
 	p.PluginObj.PluginReference = name
728 728
 
729 729
 	pm.publisher.Publish(EventCreate{Plugin: p.PluginObj})
730
-	pm.config.LogPluginEvent(p.PluginObj.ID, name, "create")
730
+	pm.config.LogPluginEvent(p.PluginObj.ID, name, events.ActionCreate)
731 731
 
732 732
 	return nil
733 733
 }
... ...
@@ -17,6 +17,7 @@ import (
17 17
 	"github.com/containerd/containerd/content/local"
18 18
 	"github.com/containerd/containerd/log"
19 19
 	"github.com/docker/docker/api/types"
20
+	"github.com/docker/docker/api/types/events"
20 21
 	"github.com/docker/docker/pkg/authorization"
21 22
 	"github.com/docker/docker/pkg/containerfs"
22 23
 	"github.com/docker/docker/pkg/ioutils"
... ...
@@ -56,7 +57,7 @@ func (pm *Manager) restorePlugin(p *v2.Plugin, c *controller) error {
56 56
 	return nil
57 57
 }
58 58
 
59
-type eventLogger func(id, name, action string)
59
+type eventLogger func(id, name string, action events.Action)
60 60
 
61 61
 // ManagerConfig defines configuration needed to start new manager.
62 62
 type ManagerConfig struct {
... ...
@@ -9,6 +9,7 @@ import (
9 9
 	"testing"
10 10
 
11 11
 	"github.com/docker/docker/api/types"
12
+	"github.com/docker/docker/api/types/events"
12 13
 	"github.com/docker/docker/pkg/containerfs"
13 14
 	"github.com/docker/docker/pkg/stringid"
14 15
 	v2 "github.com/docker/docker/plugin/v2"
... ...
@@ -40,7 +41,7 @@ func TestManagerWithPluginMounts(t *testing.T) {
40 40
 			Root:           managerRoot,
41 41
 			ExecRoot:       filepath.Join(root, "exec"),
42 42
 			CreateExecutor: func(*Manager) (Executor, error) { return nil, nil },
43
-			LogPluginEvent: func(_, _, _ string) {},
43
+			LogPluginEvent: func(_, _ string, _ events.Action) {},
44 44
 		})
45 45
 	if err != nil {
46 46
 		t.Fatal(err)
... ...
@@ -112,7 +113,7 @@ func TestCreateFailed(t *testing.T) {
112 112
 			Root:           managerRoot,
113 113
 			ExecRoot:       filepath.Join(root, "exec"),
114 114
 			CreateExecutor: func(*Manager) (Executor, error) { return &simpleExecutor{}, nil },
115
-			LogPluginEvent: func(_, _, _ string) {},
115
+			LogPluginEvent: func(_, _ string, _ events.Action) {},
116 116
 		})
117 117
 	if err != nil {
118 118
 		t.Fatal(err)
... ...
@@ -181,13 +182,13 @@ func TestPluginAlreadyRunningOnStartup(t *testing.T) {
181 181
 		{
182 182
 			desc: "live-restore-disabled",
183 183
 			config: ManagerConfig{
184
-				LogPluginEvent: func(_, _, _ string) {},
184
+				LogPluginEvent: func(_, _ string, _ events.Action) {},
185 185
 			},
186 186
 		},
187 187
 		{
188 188
 			desc: "live-restore-enabled",
189 189
 			config: ManagerConfig{
190
-				LogPluginEvent:     func(_, _, _ string) {},
190
+				LogPluginEvent:     func(_, _ string, _ events.Action) {},
191 191
 				LiveRestoreEnabled: true,
192 192
 			},
193 193
 		},
... ...
@@ -781,7 +781,7 @@ func (d *Daemon) ReloadConfig() error {
781 781
 			if e.Type != events.DaemonEventType {
782 782
 				continue
783 783
 			}
784
-			if e.Action != "reload" {
784
+			if e.Action != events.ActionReload {
785 785
 				continue
786 786
 			}
787 787
 			close(errCh) // notify that we are done
... ...
@@ -10,6 +10,7 @@ import (
10 10
 	"time"
11 11
 
12 12
 	"github.com/docker/docker/api/types"
13
+	"github.com/docker/docker/api/types/events"
13 14
 	"github.com/docker/docker/api/types/registry"
14 15
 	"github.com/docker/docker/pkg/archive"
15 16
 	"github.com/docker/docker/plugin"
... ...
@@ -117,7 +118,7 @@ func CreateInRegistry(ctx context.Context, repo string, auth *registry.AuthConfi
117 117
 		Root:            filepath.Join(tmpDir, "root"),
118 118
 		ExecRoot:        "/run/docker", // manager init fails if not set
119 119
 		CreateExecutor:  dummyExec,
120
-		LogPluginEvent:  func(id, name, action string) {}, // panics when not set
120
+		LogPluginEvent:  func(id, name string, action events.Action) {}, // panics when not set
121 121
 	}
122 122
 	manager, err := plugin.NewManager(managerConfig)
123 123
 	if err != nil {
... ...
@@ -7,6 +7,7 @@ import (
7 7
 
8 8
 	"github.com/containerd/containerd/log"
9 9
 	"github.com/docker/docker/api/types"
10
+	"github.com/docker/docker/api/types/events"
10 11
 	"github.com/docker/docker/api/types/filters"
11 12
 	volumetypes "github.com/docker/docker/api/types/volume"
12 13
 	"github.com/docker/docker/errdefs"
... ...
@@ -27,7 +28,7 @@ type ds interface {
27 27
 // VolumeEventLogger interface provides methods to log volume-related events
28 28
 type VolumeEventLogger interface {
29 29
 	// LogVolumeEvent generates an event related to a volume.
30
-	LogVolumeEvent(volumeID, action string, attributes map[string]string)
30
+	LogVolumeEvent(volumeID string, action events.Action, attributes map[string]string)
31 31
 }
32 32
 
33 33
 // VolumesService manages access to volumes
... ...
@@ -248,7 +249,7 @@ func (s *VolumesService) Prune(ctx context.Context, filter filters.Args) (*types
248 248
 		rep.SpaceReclaimed += uint64(vSize)
249 249
 		rep.VolumesDeleted = append(rep.VolumesDeleted, v.Name())
250 250
 	}
251
-	s.eventLogger.LogVolumeEvent("", "prune", map[string]string{
251
+	s.eventLogger.LogVolumeEvent("", events.ActionPrune, map[string]string{
252 252
 		"reclaimed": strconv.FormatInt(int64(rep.SpaceReclaimed), 10),
253 253
 	})
254 254
 	return rep, nil
... ...
@@ -5,6 +5,7 @@ import (
5 5
 	"os"
6 6
 	"testing"
7 7
 
8
+	"github.com/docker/docker/api/types/events"
8 9
 	"github.com/docker/docker/api/types/filters"
9 10
 	"github.com/docker/docker/errdefs"
10 11
 	"github.com/docker/docker/volume"
... ...
@@ -248,4 +249,4 @@ func newTestService(t *testing.T, ds *volumedrivers.Store) (*VolumesService, fun
248 248
 
249 249
 type dummyEventLogger struct{}
250 250
 
251
-func (dummyEventLogger) LogVolumeEvent(_, _ string, _ map[string]string) {}
251
+func (dummyEventLogger) LogVolumeEvent(_ string, _ events.Action, _ map[string]string) {}
... ...
@@ -10,6 +10,7 @@ import (
10 10
 	"time"
11 11
 
12 12
 	"github.com/containerd/containerd/log"
13
+	"github.com/docker/docker/api/types/events"
13 14
 	"github.com/docker/docker/errdefs"
14 15
 	"github.com/docker/docker/volume"
15 16
 	"github.com/docker/docker/volume/drivers"
... ...
@@ -501,7 +502,7 @@ func (s *VolumeStore) Create(ctx context.Context, name, driverName string, creat
501 501
 	}
502 502
 
503 503
 	if created && s.eventLogger != nil {
504
-		s.eventLogger.LogVolumeEvent(v.Name(), "create", map[string]string{"driver": v.DriverName()})
504
+		s.eventLogger.LogVolumeEvent(v.Name(), events.ActionCreate, map[string]string{"driver": v.DriverName()})
505 505
 	}
506 506
 	s.setNamed(v, cfg.Reference)
507 507
 	return v, nil
... ...
@@ -833,7 +834,7 @@ func (s *VolumeStore) Remove(ctx context.Context, v volume.Volume, rmOpts ...opt
833 833
 		}
834 834
 	}
835 835
 	if err == nil && s.eventLogger != nil {
836
-		s.eventLogger.LogVolumeEvent(v.Name(), "destroy", map[string]string{"driver": v.DriverName()})
836
+		s.eventLogger.LogVolumeEvent(v.Name(), events.ActionDestroy, map[string]string{"driver": v.DriverName()})
837 837
 	}
838 838
 	return err
839 839
 }