Browse code

Add volume events.

Signed-off-by: David Calavera <david.calavera@gmail.com>

David Calavera authored on 2015/12/22 09:45:31
Showing 12 changed files
... ...
@@ -618,7 +618,7 @@ func detachMounted(path string) error {
618 618
 }
619 619
 
620 620
 // UnmountVolumes unmounts all volumes
621
-func (container *Container) UnmountVolumes(forceSyscall bool) error {
621
+func (container *Container) UnmountVolumes(forceSyscall bool, volumeEventLog func(name, action string, attributes map[string]string)) error {
622 622
 	var (
623 623
 		volumeMounts []volume.MountPoint
624 624
 		err          error
... ...
@@ -649,6 +649,12 @@ func (container *Container) UnmountVolumes(forceSyscall bool) error {
649 649
 			if err := volumeMount.Volume.Unmount(); err != nil {
650 650
 				return err
651 651
 			}
652
+
653
+			attributes := map[string]string{
654
+				"driver":    volumeMount.Volume.DriverName(),
655
+				"container": container.ID,
656
+			}
657
+			volumeEventLog(volumeMount.Volume.Name(), "unmount", attributes)
652 658
 		}
653 659
 	}
654 660
 
... ...
@@ -39,7 +39,7 @@ func (container *Container) IpcMounts() []execdriver.Mount {
39 39
 }
40 40
 
41 41
 // UnmountVolumes explicitly unmounts volumes from the container.
42
-func (container *Container) UnmountVolumes(forceSyscall bool) error {
42
+func (container *Container) UnmountVolumes(forceSyscall bool, volumeEventLog func(name, action string, attributes map[string]string)) error {
43 43
 	return nil
44 44
 }
45 45
 
... ...
@@ -84,7 +84,7 @@ func (daemon *Daemon) containerStatPath(container *container.Container, path str
84 84
 	defer daemon.Unmount(container)
85 85
 
86 86
 	err = daemon.mountVolumes(container)
87
-	defer container.UnmountVolumes(true)
87
+	defer container.UnmountVolumes(true, daemon.LogVolumeEvent)
88 88
 	if err != nil {
89 89
 		return nil, err
90 90
 	}
... ...
@@ -119,7 +119,7 @@ func (daemon *Daemon) containerArchivePath(container *container.Container, path
119 119
 	defer func() {
120 120
 		if err != nil {
121 121
 			// unmount any volumes
122
-			container.UnmountVolumes(true)
122
+			container.UnmountVolumes(true, daemon.LogVolumeEvent)
123 123
 			// unmount the container's rootfs
124 124
 			daemon.Unmount(container)
125 125
 		}
... ...
@@ -154,7 +154,7 @@ func (daemon *Daemon) containerArchivePath(container *container.Container, path
154 154
 
155 155
 	content = ioutils.NewReadCloserWrapper(data, func() error {
156 156
 		err := data.Close()
157
-		container.UnmountVolumes(true)
157
+		container.UnmountVolumes(true, daemon.LogVolumeEvent)
158 158
 		daemon.Unmount(container)
159 159
 		container.Unlock()
160 160
 		return err
... ...
@@ -181,7 +181,7 @@ func (daemon *Daemon) containerExtractToDir(container *container.Container, path
181 181
 	defer daemon.Unmount(container)
182 182
 
183 183
 	err = daemon.mountVolumes(container)
184
-	defer container.UnmountVolumes(true)
184
+	defer container.UnmountVolumes(true, daemon.LogVolumeEvent)
185 185
 	if err != nil {
186 186
 		return err
187 187
 	}
... ...
@@ -283,7 +283,7 @@ func (daemon *Daemon) containerCopy(container *container.Container, resource str
283 283
 	defer func() {
284 284
 		if err != nil {
285 285
 			// unmount any volumes
286
-			container.UnmountVolumes(true)
286
+			container.UnmountVolumes(true, daemon.LogVolumeEvent)
287 287
 			// unmount the container's rootfs
288 288
 			daemon.Unmount(container)
289 289
 		}
... ...
@@ -320,7 +320,7 @@ func (daemon *Daemon) containerCopy(container *container.Container, resource str
320 320
 
321 321
 	reader := ioutils.NewReadCloserWrapper(archive, func() error {
322 322
 		err := archive.Close()
323
-		container.UnmountVolumes(true)
323
+		container.UnmountVolumes(true, daemon.LogVolumeEvent)
324 324
 		daemon.Unmount(container)
325 325
 		container.Unlock()
326 326
 		return err
... ...
@@ -719,6 +719,11 @@ func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, n li
719 719
 	if err := container.ToDiskLocking(); err != nil {
720 720
 		return fmt.Errorf("Error saving container to disk: %v", err)
721 721
 	}
722
+
723
+	attributes := map[string]string{
724
+		"container": container.ID,
725
+	}
726
+	daemon.LogNetworkEventWithAttributes(n, "disconnect", attributes)
722 727
 	return nil
723 728
 }
724 729
 
... ...
@@ -844,14 +849,14 @@ func (daemon *Daemon) releaseNetwork(container *container.Container) {
844 844
 	}
845 845
 
846 846
 	sid := container.NetworkSettings.SandboxID
847
-	networks := container.NetworkSettings.Networks
848
-	for n := range networks {
849
-		networks[n] = &networktypes.EndpointSettings{}
847
+	settings := container.NetworkSettings.Networks
848
+	for n := range settings {
849
+		settings[n] = &networktypes.EndpointSettings{}
850 850
 	}
851 851
 
852 852
 	container.NetworkSettings = &network.Settings{Networks: networks}
853 853
 
854
-	if sid == "" || len(networks) == 0 {
854
+	if sid == "" || len(settings) == 0 {
855 855
 		return
856 856
 	}
857 857
 
... ...
@@ -864,6 +869,13 @@ func (daemon *Daemon) releaseNetwork(container *container.Container) {
864 864
 	if err := sb.Delete(); err != nil {
865 865
 		logrus.Errorf("Error deleting sandbox id %s for container %s: %v", sid, container.ID, err)
866 866
 	}
867
+
868
+	attributes := map[string]string{
869
+		"container": container.ID,
870
+	}
871
+	for nwID := range settings {
872
+		daemon.logNetworkEventWithID(nwID, "disconnect", attributes)
873
+	}
867 874
 }
868 875
 
869 876
 func (daemon *Daemon) setupIpcDirs(c *container.Container) error {
... ...
@@ -169,5 +169,10 @@ func (daemon *Daemon) VolumeCreate(name, driverName string, opts map[string]stri
169 169
 	if (driverName != "" && v.DriverName() != driverName) || (driverName == "" && v.DriverName() != volume.DefaultDriverName) {
170 170
 		return nil, derr.ErrorVolumeNameTaken.WithArgs(name, v.DriverName())
171 171
 	}
172
+
173
+	if driverName == "" {
174
+		driverName = volume.DefaultDriverName
175
+	}
176
+	daemon.LogVolumeEvent(name, "create", map[string]string{"driver": driverName})
172 177
 	return volumeToAPIType(v), nil
173 178
 }
... ...
@@ -157,5 +157,6 @@ func (daemon *Daemon) VolumeRm(name string) error {
157 157
 		}
158 158
 		return derr.ErrorCodeRmVolume.WithArgs(name, err)
159 159
 	}
160
+	daemon.LogVolumeEvent(v.Name(), "destroy", map[string]string{"driver": v.DriverName()})
160 161
 	return nil
161 162
 }
... ...
@@ -61,9 +61,12 @@ func (daemon *Daemon) LogNetworkEvent(nw libnetwork.Network, action string) {
61 61
 func (daemon *Daemon) LogNetworkEventWithAttributes(nw libnetwork.Network, action string, attributes map[string]string) {
62 62
 	attributes["name"] = nw.Name()
63 63
 	attributes["type"] = nw.Type()
64
+	daemon.logNetworkEventWithID(nw.ID(), action, attributes)
65
+}
64 66
 
67
+func (daemon *Daemon) logNetworkEventWithID(id, action string, attributes map[string]string) {
65 68
 	actor := events.Actor{
66
-		ID:         nw.ID(),
69
+		ID:         id,
67 70
 		Attributes: attributes,
68 71
 	}
69 72
 	daemon.EventsService.Log(action, events.NetworkEventType, actor)
... ...
@@ -156,7 +156,7 @@ func (daemon *Daemon) Cleanup(container *container.Container) {
156 156
 		daemon.unregisterExecCommand(container, eConfig)
157 157
 	}
158 158
 
159
-	if err := container.UnmountVolumes(false); err != nil {
159
+	if err := container.UnmountVolumes(false, daemon.LogVolumeEvent); err != nil {
160 160
 		logrus.Warnf("%s cleanup: Failed to umount volumes: %v", container.ID, err)
161 161
 	}
162 162
 }
... ...
@@ -5,6 +5,7 @@ package daemon
5 5
 import (
6 6
 	"os"
7 7
 	"sort"
8
+	"strconv"
8 9
 
9 10
 	"github.com/docker/docker/container"
10 11
 	"github.com/docker/docker/daemon/execdriver"
... ...
@@ -30,6 +31,16 @@ func (daemon *Daemon) setupMounts(container *container.Container) ([]execdriver.
30 30
 				Writable:    m.RW,
31 31
 				Propagation: m.Propagation,
32 32
 			}
33
+			if m.Volume != nil {
34
+				attributes := map[string]string{
35
+					"driver":      m.Volume.DriverName(),
36
+					"container":   container.ID,
37
+					"destination": m.Destination,
38
+					"read/write":  strconv.FormatBool(m.RW),
39
+					"propagation": m.Propagation,
40
+				}
41
+				daemon.LogVolumeEvent(m.Volume.Name(), "mount", attributes)
42
+			}
33 43
 			mounts = append(mounts, mnt)
34 44
 		}
35 45
 	}
... ...
@@ -402,11 +402,6 @@ func (s *DockerSuite) TestEventsFilterContainer(c *check.C) {
402 402
 func (s *DockerSuite) TestEventsStreaming(c *check.C) {
403 403
 	testRequires(c, DaemonIsLinux)
404 404
 
405
-	eventCreate := make(chan struct{})
406
-	eventStart := make(chan struct{})
407
-	eventDie := make(chan struct{})
408
-	eventDestroy := make(chan struct{})
409
-
410 405
 	observer, err := newEventObserver(c)
411 406
 	c.Assert(err, checker.IsNil)
412 407
 	err = observer.Start()
... ...
@@ -415,42 +410,21 @@ func (s *DockerSuite) TestEventsStreaming(c *check.C) {
415 415
 
416 416
 	out, _ := dockerCmd(c, "run", "-d", "busybox:latest", "true")
417 417
 	containerID := strings.TrimSpace(out)
418
-	matchCreate := regexp.MustCompile(containerID + `: \(from busybox:latest\) create\z`)
419
-	matchStart := regexp.MustCompile(containerID + `: \(from busybox:latest\) start\z`)
420
-	matchDie := regexp.MustCompile(containerID + `: \(from busybox:latest\) die\z`)
421
-	matchDestroy := regexp.MustCompile(containerID + `: \(from busybox:latest\) destroy\z`)
422
-
423
-	matcher := func(text string) {
424
-		switch {
425
-		case matchCreate.MatchString(text):
426
-			close(eventCreate)
427
-		case matchStart.MatchString(text):
428
-			close(eventStart)
429
-		case matchDie.MatchString(text):
430
-			close(eventDie)
431
-		case matchDestroy.MatchString(text):
432
-			close(eventDestroy)
433
-		}
434
-	}
435
-	go observer.Match(matcher)
436 418
 
437
-	select {
438
-	case <-time.After(5 * time.Second):
439
-		c.Fatal(observer.TimeoutError(containerID, "create"))
440
-	case <-testActions["create"]:
441
-		// ignore, done
419
+	testActions := map[string]chan bool{
420
+		"create":  make(chan bool),
421
+		"start":   make(chan bool),
422
+		"die":     make(chan bool),
423
+		"destroy": make(chan bool),
442 424
 	}
443 425
 
444
-	select {
445
-	case <-time.After(5 * time.Second):
446
-		c.Fatal(observer.TimeoutError(containerID, "start"))
447
-	case <-testActions["start"]:
448
-		// ignore, done
449
-	}
426
+	go observer.Match(matchEventLine(containerID, "container", testActions))
450 427
 
451 428
 	select {
452 429
 	case <-time.After(5 * time.Second):
453
-		c.Fatal(observer.TimeoutError(containerID, "die"))
430
+		c.Fatal(observer.TimeoutError(containerID, "create/start/die"))
431
+	case <-testActions["create"]:
432
+	case <-testActions["start"]:
454 433
 	case <-testActions["die"]:
455 434
 		// ignore, done
456 435
 	}
... ...
@@ -460,7 +434,7 @@ func (s *DockerSuite) TestEventsStreaming(c *check.C) {
460 460
 	select {
461 461
 	case <-time.After(5 * time.Second):
462 462
 		c.Fatal(observer.TimeoutError(containerID, "destroy"))
463
-	case <-eventDestroy:
463
+	case <-testActions["destroy"]:
464 464
 		// ignore, done
465 465
 	}
466 466
 }
... ...
@@ -151,3 +151,29 @@ func (s *DockerSuite) TestEventsContainerFilterBeforeCreate(c *check.C) {
151 151
 	<-ch
152 152
 	c.Assert(out, checker.Contains, cID, check.Commentf("Missing event of container (foo)"))
153 153
 }
154
+
155
+func (s *DockerSuite) TestVolumeEvents(c *check.C) {
156
+	testRequires(c, DaemonIsLinux)
157
+
158
+	since := daemonTime(c).Unix()
159
+
160
+	// Observe create/mount volume actions
161
+	dockerCmd(c, "volume", "create", "--name", "test-event-volume-local")
162
+	dockerCmd(c, "run", "--name", "test-volume-container", "--volume", "test-event-volume-local:/foo", "-d", "busybox", "true")
163
+	waitRun("test-volume-container")
164
+
165
+	// Observe unmount/destroy volume actions
166
+	dockerCmd(c, "rm", "-f", "test-volume-container")
167
+	dockerCmd(c, "volume", "rm", "test-event-volume-local")
168
+
169
+	out, _ := dockerCmd(c, "events", fmt.Sprintf("--since=%d", since), fmt.Sprintf("--until=%d", daemonTime(c).Unix()))
170
+	events := strings.Split(strings.TrimSpace(out), "\n")
171
+	c.Assert(len(events), checker.GreaterThan, 4)
172
+
173
+	volumeEvents := eventActionsByIDAndType(c, events, "test-event-volume-local", "volume")
174
+	c.Assert(volumeEvents, checker.HasLen, 4)
175
+	c.Assert(volumeEvents[0], checker.Equals, "create")
176
+	c.Assert(volumeEvents[1], checker.Equals, "mount")
177
+	c.Assert(volumeEvents[2], checker.Equals, "unmount")
178
+	c.Assert(volumeEvents[3], checker.Equals, "destroy")
179
+}
... ...
@@ -6,6 +6,7 @@ import (
6 6
 	"fmt"
7 7
 	"io"
8 8
 	"os/exec"
9
+	"regexp"
9 10
 	"strconv"
10 11
 	"strings"
11 12