mirror of
				https://github.com/moby/moby.git
				synced 2022-11-09 12:21:53 -05:00 
			
		
		
		
	Add volume events.
Signed-off-by: David Calavera <david.calavera@gmail.com>
This commit is contained in:
		
							parent
							
								
									72f1881df1
								
							
						
					
					
						commit
						9d12d09300
					
				
					 12 changed files with 88 additions and 49 deletions
				
			
		| 
						 | 
				
			
			@ -618,7 +618,7 @@ func detachMounted(path string) error {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// UnmountVolumes unmounts all volumes
 | 
			
		||||
func (container *Container) UnmountVolumes(forceSyscall bool) error {
 | 
			
		||||
func (container *Container) UnmountVolumes(forceSyscall bool, volumeEventLog func(name, action string, attributes map[string]string)) error {
 | 
			
		||||
	var (
 | 
			
		||||
		volumeMounts []volume.MountPoint
 | 
			
		||||
		err          error
 | 
			
		||||
| 
						 | 
				
			
			@ -649,6 +649,12 @@ func (container *Container) UnmountVolumes(forceSyscall bool) error {
 | 
			
		|||
			if err := volumeMount.Volume.Unmount(); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			attributes := map[string]string{
 | 
			
		||||
				"driver":    volumeMount.Volume.DriverName(),
 | 
			
		||||
				"container": container.ID,
 | 
			
		||||
			}
 | 
			
		||||
			volumeEventLog(volumeMount.Volume.Name(), "unmount", attributes)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,7 +39,7 @@ func (container *Container) IpcMounts() []execdriver.Mount {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// UnmountVolumes explicitly unmounts volumes from the container.
 | 
			
		||||
func (container *Container) UnmountVolumes(forceSyscall bool) error {
 | 
			
		||||
func (container *Container) UnmountVolumes(forceSyscall bool, volumeEventLog func(name, action string, attributes map[string]string)) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -84,7 +84,7 @@ func (daemon *Daemon) containerStatPath(container *container.Container, path str
 | 
			
		|||
	defer daemon.Unmount(container)
 | 
			
		||||
 | 
			
		||||
	err = daemon.mountVolumes(container)
 | 
			
		||||
	defer container.UnmountVolumes(true)
 | 
			
		||||
	defer container.UnmountVolumes(true, daemon.LogVolumeEvent)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -119,7 +119,7 @@ func (daemon *Daemon) containerArchivePath(container *container.Container, path
 | 
			
		|||
	defer func() {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			// unmount any volumes
 | 
			
		||||
			container.UnmountVolumes(true)
 | 
			
		||||
			container.UnmountVolumes(true, daemon.LogVolumeEvent)
 | 
			
		||||
			// unmount the container's rootfs
 | 
			
		||||
			daemon.Unmount(container)
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -154,7 +154,7 @@ func (daemon *Daemon) containerArchivePath(container *container.Container, path
 | 
			
		|||
 | 
			
		||||
	content = ioutils.NewReadCloserWrapper(data, func() error {
 | 
			
		||||
		err := data.Close()
 | 
			
		||||
		container.UnmountVolumes(true)
 | 
			
		||||
		container.UnmountVolumes(true, daemon.LogVolumeEvent)
 | 
			
		||||
		daemon.Unmount(container)
 | 
			
		||||
		container.Unlock()
 | 
			
		||||
		return err
 | 
			
		||||
| 
						 | 
				
			
			@ -181,7 +181,7 @@ func (daemon *Daemon) containerExtractToDir(container *container.Container, path
 | 
			
		|||
	defer daemon.Unmount(container)
 | 
			
		||||
 | 
			
		||||
	err = daemon.mountVolumes(container)
 | 
			
		||||
	defer container.UnmountVolumes(true)
 | 
			
		||||
	defer container.UnmountVolumes(true, daemon.LogVolumeEvent)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -283,7 +283,7 @@ func (daemon *Daemon) containerCopy(container *container.Container, resource str
 | 
			
		|||
	defer func() {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			// unmount any volumes
 | 
			
		||||
			container.UnmountVolumes(true)
 | 
			
		||||
			container.UnmountVolumes(true, daemon.LogVolumeEvent)
 | 
			
		||||
			// unmount the container's rootfs
 | 
			
		||||
			daemon.Unmount(container)
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -320,7 +320,7 @@ func (daemon *Daemon) containerCopy(container *container.Container, resource str
 | 
			
		|||
 | 
			
		||||
	reader := ioutils.NewReadCloserWrapper(archive, func() error {
 | 
			
		||||
		err := archive.Close()
 | 
			
		||||
		container.UnmountVolumes(true)
 | 
			
		||||
		container.UnmountVolumes(true, daemon.LogVolumeEvent)
 | 
			
		||||
		daemon.Unmount(container)
 | 
			
		||||
		container.Unlock()
 | 
			
		||||
		return err
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -719,6 +719,11 @@ func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, n li
 | 
			
		|||
	if err := container.ToDiskLocking(); err != nil {
 | 
			
		||||
		return fmt.Errorf("Error saving container to disk: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	attributes := map[string]string{
 | 
			
		||||
		"container": container.ID,
 | 
			
		||||
	}
 | 
			
		||||
	daemon.LogNetworkEventWithAttributes(n, "disconnect", attributes)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -844,14 +849,14 @@ func (daemon *Daemon) releaseNetwork(container *container.Container) {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	sid := container.NetworkSettings.SandboxID
 | 
			
		||||
	networks := container.NetworkSettings.Networks
 | 
			
		||||
	for n := range networks {
 | 
			
		||||
		networks[n] = &networktypes.EndpointSettings{}
 | 
			
		||||
	settings := container.NetworkSettings.Networks
 | 
			
		||||
	for n := range settings {
 | 
			
		||||
		settings[n] = &networktypes.EndpointSettings{}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	container.NetworkSettings = &network.Settings{Networks: networks}
 | 
			
		||||
 | 
			
		||||
	if sid == "" || len(networks) == 0 {
 | 
			
		||||
	if sid == "" || len(settings) == 0 {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -864,6 +869,13 @@ func (daemon *Daemon) releaseNetwork(container *container.Container) {
 | 
			
		|||
	if err := sb.Delete(); err != nil {
 | 
			
		||||
		logrus.Errorf("Error deleting sandbox id %s for container %s: %v", sid, container.ID, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	attributes := map[string]string{
 | 
			
		||||
		"container": container.ID,
 | 
			
		||||
	}
 | 
			
		||||
	for nwID := range settings {
 | 
			
		||||
		daemon.logNetworkEventWithID(nwID, "disconnect", attributes)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (daemon *Daemon) setupIpcDirs(c *container.Container) error {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -169,5 +169,10 @@ func (daemon *Daemon) VolumeCreate(name, driverName string, opts map[string]stri
 | 
			
		|||
	if (driverName != "" && v.DriverName() != driverName) || (driverName == "" && v.DriverName() != volume.DefaultDriverName) {
 | 
			
		||||
		return nil, derr.ErrorVolumeNameTaken.WithArgs(name, v.DriverName())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if driverName == "" {
 | 
			
		||||
		driverName = volume.DefaultDriverName
 | 
			
		||||
	}
 | 
			
		||||
	daemon.LogVolumeEvent(name, "create", map[string]string{"driver": driverName})
 | 
			
		||||
	return volumeToAPIType(v), nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -157,5 +157,6 @@ func (daemon *Daemon) VolumeRm(name string) error {
 | 
			
		|||
		}
 | 
			
		||||
		return derr.ErrorCodeRmVolume.WithArgs(name, err)
 | 
			
		||||
	}
 | 
			
		||||
	daemon.LogVolumeEvent(v.Name(), "destroy", map[string]string{"driver": v.DriverName()})
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -61,9 +61,12 @@ func (daemon *Daemon) LogNetworkEvent(nw libnetwork.Network, action string) {
 | 
			
		|||
func (daemon *Daemon) LogNetworkEventWithAttributes(nw libnetwork.Network, action string, attributes map[string]string) {
 | 
			
		||||
	attributes["name"] = nw.Name()
 | 
			
		||||
	attributes["type"] = nw.Type()
 | 
			
		||||
	daemon.logNetworkEventWithID(nw.ID(), action, attributes)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (daemon *Daemon) logNetworkEventWithID(id, action string, attributes map[string]string) {
 | 
			
		||||
	actor := events.Actor{
 | 
			
		||||
		ID:         nw.ID(),
 | 
			
		||||
		ID:         id,
 | 
			
		||||
		Attributes: attributes,
 | 
			
		||||
	}
 | 
			
		||||
	daemon.EventsService.Log(action, events.NetworkEventType, actor)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -156,7 +156,7 @@ func (daemon *Daemon) Cleanup(container *container.Container) {
 | 
			
		|||
		daemon.unregisterExecCommand(container, eConfig)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := container.UnmountVolumes(false); err != nil {
 | 
			
		||||
	if err := container.UnmountVolumes(false, daemon.LogVolumeEvent); err != nil {
 | 
			
		||||
		logrus.Warnf("%s cleanup: Failed to umount volumes: %v", container.ID, err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,7 @@ package daemon
 | 
			
		|||
import (
 | 
			
		||||
	"os"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strconv"
 | 
			
		||||
 | 
			
		||||
	"github.com/docker/docker/container"
 | 
			
		||||
	"github.com/docker/docker/daemon/execdriver"
 | 
			
		||||
| 
						 | 
				
			
			@ -30,6 +31,16 @@ func (daemon *Daemon) setupMounts(container *container.Container) ([]execdriver.
 | 
			
		|||
				Writable:    m.RW,
 | 
			
		||||
				Propagation: m.Propagation,
 | 
			
		||||
			}
 | 
			
		||||
			if m.Volume != nil {
 | 
			
		||||
				attributes := map[string]string{
 | 
			
		||||
					"driver":      m.Volume.DriverName(),
 | 
			
		||||
					"container":   container.ID,
 | 
			
		||||
					"destination": m.Destination,
 | 
			
		||||
					"read/write":  strconv.FormatBool(m.RW),
 | 
			
		||||
					"propagation": m.Propagation,
 | 
			
		||||
				}
 | 
			
		||||
				daemon.LogVolumeEvent(m.Volume.Name(), "mount", attributes)
 | 
			
		||||
			}
 | 
			
		||||
			mounts = append(mounts, mnt)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -402,11 +402,6 @@ func (s *DockerSuite) TestEventsFilterContainer(c *check.C) {
 | 
			
		|||
func (s *DockerSuite) TestEventsStreaming(c *check.C) {
 | 
			
		||||
	testRequires(c, DaemonIsLinux)
 | 
			
		||||
 | 
			
		||||
	eventCreate := make(chan struct{})
 | 
			
		||||
	eventStart := make(chan struct{})
 | 
			
		||||
	eventDie := make(chan struct{})
 | 
			
		||||
	eventDestroy := make(chan struct{})
 | 
			
		||||
 | 
			
		||||
	observer, err := newEventObserver(c)
 | 
			
		||||
	c.Assert(err, checker.IsNil)
 | 
			
		||||
	err = observer.Start()
 | 
			
		||||
| 
						 | 
				
			
			@ -415,42 +410,21 @@ func (s *DockerSuite) TestEventsStreaming(c *check.C) {
 | 
			
		|||
 | 
			
		||||
	out, _ := dockerCmd(c, "run", "-d", "busybox:latest", "true")
 | 
			
		||||
	containerID := strings.TrimSpace(out)
 | 
			
		||||
	matchCreate := regexp.MustCompile(containerID + `: \(from busybox:latest\) create\z`)
 | 
			
		||||
	matchStart := regexp.MustCompile(containerID + `: \(from busybox:latest\) start\z`)
 | 
			
		||||
	matchDie := regexp.MustCompile(containerID + `: \(from busybox:latest\) die\z`)
 | 
			
		||||
	matchDestroy := regexp.MustCompile(containerID + `: \(from busybox:latest\) destroy\z`)
 | 
			
		||||
 | 
			
		||||
	matcher := func(text string) {
 | 
			
		||||
		switch {
 | 
			
		||||
		case matchCreate.MatchString(text):
 | 
			
		||||
			close(eventCreate)
 | 
			
		||||
		case matchStart.MatchString(text):
 | 
			
		||||
			close(eventStart)
 | 
			
		||||
		case matchDie.MatchString(text):
 | 
			
		||||
			close(eventDie)
 | 
			
		||||
		case matchDestroy.MatchString(text):
 | 
			
		||||
			close(eventDestroy)
 | 
			
		||||
		}
 | 
			
		||||
	testActions := map[string]chan bool{
 | 
			
		||||
		"create":  make(chan bool),
 | 
			
		||||
		"start":   make(chan bool),
 | 
			
		||||
		"die":     make(chan bool),
 | 
			
		||||
		"destroy": make(chan bool),
 | 
			
		||||
	}
 | 
			
		||||
	go observer.Match(matcher)
 | 
			
		||||
 | 
			
		||||
	go observer.Match(matchEventLine(containerID, "container", testActions))
 | 
			
		||||
 | 
			
		||||
	select {
 | 
			
		||||
	case <-time.After(5 * time.Second):
 | 
			
		||||
		c.Fatal(observer.TimeoutError(containerID, "create"))
 | 
			
		||||
		c.Fatal(observer.TimeoutError(containerID, "create/start/die"))
 | 
			
		||||
	case <-testActions["create"]:
 | 
			
		||||
		// ignore, done
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	select {
 | 
			
		||||
	case <-time.After(5 * time.Second):
 | 
			
		||||
		c.Fatal(observer.TimeoutError(containerID, "start"))
 | 
			
		||||
	case <-testActions["start"]:
 | 
			
		||||
		// ignore, done
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	select {
 | 
			
		||||
	case <-time.After(5 * time.Second):
 | 
			
		||||
		c.Fatal(observer.TimeoutError(containerID, "die"))
 | 
			
		||||
	case <-testActions["die"]:
 | 
			
		||||
		// ignore, done
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -460,7 +434,7 @@ func (s *DockerSuite) TestEventsStreaming(c *check.C) {
 | 
			
		|||
	select {
 | 
			
		||||
	case <-time.After(5 * time.Second):
 | 
			
		||||
		c.Fatal(observer.TimeoutError(containerID, "destroy"))
 | 
			
		||||
	case <-eventDestroy:
 | 
			
		||||
	case <-testActions["destroy"]:
 | 
			
		||||
		// ignore, done
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -151,3 +151,29 @@ func (s *DockerSuite) TestEventsContainerFilterBeforeCreate(c *check.C) {
 | 
			
		|||
	<-ch
 | 
			
		||||
	c.Assert(out, checker.Contains, cID, check.Commentf("Missing event of container (foo)"))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *DockerSuite) TestVolumeEvents(c *check.C) {
 | 
			
		||||
	testRequires(c, DaemonIsLinux)
 | 
			
		||||
 | 
			
		||||
	since := daemonTime(c).Unix()
 | 
			
		||||
 | 
			
		||||
	// Observe create/mount volume actions
 | 
			
		||||
	dockerCmd(c, "volume", "create", "--name", "test-event-volume-local")
 | 
			
		||||
	dockerCmd(c, "run", "--name", "test-volume-container", "--volume", "test-event-volume-local:/foo", "-d", "busybox", "true")
 | 
			
		||||
	waitRun("test-volume-container")
 | 
			
		||||
 | 
			
		||||
	// Observe unmount/destroy volume actions
 | 
			
		||||
	dockerCmd(c, "rm", "-f", "test-volume-container")
 | 
			
		||||
	dockerCmd(c, "volume", "rm", "test-event-volume-local")
 | 
			
		||||
 | 
			
		||||
	out, _ := dockerCmd(c, "events", fmt.Sprintf("--since=%d", since), fmt.Sprintf("--until=%d", daemonTime(c).Unix()))
 | 
			
		||||
	events := strings.Split(strings.TrimSpace(out), "\n")
 | 
			
		||||
	c.Assert(len(events), checker.GreaterThan, 4)
 | 
			
		||||
 | 
			
		||||
	volumeEvents := eventActionsByIDAndType(c, events, "test-event-volume-local", "volume")
 | 
			
		||||
	c.Assert(volumeEvents, checker.HasLen, 4)
 | 
			
		||||
	c.Assert(volumeEvents[0], checker.Equals, "create")
 | 
			
		||||
	c.Assert(volumeEvents[1], checker.Equals, "mount")
 | 
			
		||||
	c.Assert(volumeEvents[2], checker.Equals, "unmount")
 | 
			
		||||
	c.Assert(volumeEvents[3], checker.Equals, "destroy")
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,7 @@ import (
 | 
			
		|||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"os/exec"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue