Add volume events.

Signed-off-by: David Calavera <david.calavera@gmail.com>
This commit is contained in:
David Calavera 2015-12-21 19:45:31 -05:00
parent 72f1881df1
commit 9d12d09300
12 changed files with 88 additions and 49 deletions

View File

@ -618,7 +618,7 @@ func detachMounted(path string) error {
} }
// UnmountVolumes unmounts all volumes // 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 ( var (
volumeMounts []volume.MountPoint volumeMounts []volume.MountPoint
err error err error
@ -649,6 +649,12 @@ func (container *Container) UnmountVolumes(forceSyscall bool) error {
if err := volumeMount.Volume.Unmount(); err != nil { if err := volumeMount.Volume.Unmount(); err != nil {
return err return err
} }
attributes := map[string]string{
"driver": volumeMount.Volume.DriverName(),
"container": container.ID,
}
volumeEventLog(volumeMount.Volume.Name(), "unmount", attributes)
} }
} }

View File

@ -39,7 +39,7 @@ func (container *Container) IpcMounts() []execdriver.Mount {
} }
// UnmountVolumes explicitly unmounts volumes from the container. // 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 return nil
} }

View File

@ -84,7 +84,7 @@ func (daemon *Daemon) containerStatPath(container *container.Container, path str
defer daemon.Unmount(container) defer daemon.Unmount(container)
err = daemon.mountVolumes(container) err = daemon.mountVolumes(container)
defer container.UnmountVolumes(true) defer container.UnmountVolumes(true, daemon.LogVolumeEvent)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -119,7 +119,7 @@ func (daemon *Daemon) containerArchivePath(container *container.Container, path
defer func() { defer func() {
if err != nil { if err != nil {
// unmount any volumes // unmount any volumes
container.UnmountVolumes(true) container.UnmountVolumes(true, daemon.LogVolumeEvent)
// unmount the container's rootfs // unmount the container's rootfs
daemon.Unmount(container) daemon.Unmount(container)
} }
@ -154,7 +154,7 @@ func (daemon *Daemon) containerArchivePath(container *container.Container, path
content = ioutils.NewReadCloserWrapper(data, func() error { content = ioutils.NewReadCloserWrapper(data, func() error {
err := data.Close() err := data.Close()
container.UnmountVolumes(true) container.UnmountVolumes(true, daemon.LogVolumeEvent)
daemon.Unmount(container) daemon.Unmount(container)
container.Unlock() container.Unlock()
return err return err
@ -181,7 +181,7 @@ func (daemon *Daemon) containerExtractToDir(container *container.Container, path
defer daemon.Unmount(container) defer daemon.Unmount(container)
err = daemon.mountVolumes(container) err = daemon.mountVolumes(container)
defer container.UnmountVolumes(true) defer container.UnmountVolumes(true, daemon.LogVolumeEvent)
if err != nil { if err != nil {
return err return err
} }
@ -283,7 +283,7 @@ func (daemon *Daemon) containerCopy(container *container.Container, resource str
defer func() { defer func() {
if err != nil { if err != nil {
// unmount any volumes // unmount any volumes
container.UnmountVolumes(true) container.UnmountVolumes(true, daemon.LogVolumeEvent)
// unmount the container's rootfs // unmount the container's rootfs
daemon.Unmount(container) daemon.Unmount(container)
} }
@ -320,7 +320,7 @@ func (daemon *Daemon) containerCopy(container *container.Container, resource str
reader := ioutils.NewReadCloserWrapper(archive, func() error { reader := ioutils.NewReadCloserWrapper(archive, func() error {
err := archive.Close() err := archive.Close()
container.UnmountVolumes(true) container.UnmountVolumes(true, daemon.LogVolumeEvent)
daemon.Unmount(container) daemon.Unmount(container)
container.Unlock() container.Unlock()
return err return err

View File

@ -719,6 +719,11 @@ func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, n li
if err := container.ToDiskLocking(); err != nil { if err := container.ToDiskLocking(); err != nil {
return fmt.Errorf("Error saving container to disk: %v", err) return fmt.Errorf("Error saving container to disk: %v", err)
} }
attributes := map[string]string{
"container": container.ID,
}
daemon.LogNetworkEventWithAttributes(n, "disconnect", attributes)
return nil return nil
} }
@ -844,14 +849,14 @@ func (daemon *Daemon) releaseNetwork(container *container.Container) {
} }
sid := container.NetworkSettings.SandboxID sid := container.NetworkSettings.SandboxID
networks := container.NetworkSettings.Networks settings := container.NetworkSettings.Networks
for n := range networks { for n := range settings {
networks[n] = &networktypes.EndpointSettings{} settings[n] = &networktypes.EndpointSettings{}
} }
container.NetworkSettings = &network.Settings{Networks: networks} container.NetworkSettings = &network.Settings{Networks: networks}
if sid == "" || len(networks) == 0 { if sid == "" || len(settings) == 0 {
return return
} }
@ -864,6 +869,13 @@ func (daemon *Daemon) releaseNetwork(container *container.Container) {
if err := sb.Delete(); err != nil { if err := sb.Delete(); err != nil {
logrus.Errorf("Error deleting sandbox id %s for container %s: %v", sid, container.ID, err) 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 { func (daemon *Daemon) setupIpcDirs(c *container.Container) error {

View File

@ -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) { if (driverName != "" && v.DriverName() != driverName) || (driverName == "" && v.DriverName() != volume.DefaultDriverName) {
return nil, derr.ErrorVolumeNameTaken.WithArgs(name, v.DriverName()) 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 return volumeToAPIType(v), nil
} }

View File

@ -157,5 +157,6 @@ func (daemon *Daemon) VolumeRm(name string) error {
} }
return derr.ErrorCodeRmVolume.WithArgs(name, err) return derr.ErrorCodeRmVolume.WithArgs(name, err)
} }
daemon.LogVolumeEvent(v.Name(), "destroy", map[string]string{"driver": v.DriverName()})
return nil return nil
} }

View File

@ -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) { func (daemon *Daemon) LogNetworkEventWithAttributes(nw libnetwork.Network, action string, attributes map[string]string) {
attributes["name"] = nw.Name() attributes["name"] = nw.Name()
attributes["type"] = nw.Type() attributes["type"] = nw.Type()
daemon.logNetworkEventWithID(nw.ID(), action, attributes)
}
func (daemon *Daemon) logNetworkEventWithID(id, action string, attributes map[string]string) {
actor := events.Actor{ actor := events.Actor{
ID: nw.ID(), ID: id,
Attributes: attributes, Attributes: attributes,
} }
daemon.EventsService.Log(action, events.NetworkEventType, actor) daemon.EventsService.Log(action, events.NetworkEventType, actor)

View File

@ -156,7 +156,7 @@ func (daemon *Daemon) Cleanup(container *container.Container) {
daemon.unregisterExecCommand(container, eConfig) 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) logrus.Warnf("%s cleanup: Failed to umount volumes: %v", container.ID, err)
} }
} }

View File

@ -5,6 +5,7 @@ package daemon
import ( import (
"os" "os"
"sort" "sort"
"strconv"
"github.com/docker/docker/container" "github.com/docker/docker/container"
"github.com/docker/docker/daemon/execdriver" "github.com/docker/docker/daemon/execdriver"
@ -30,6 +31,16 @@ func (daemon *Daemon) setupMounts(container *container.Container) ([]execdriver.
Writable: m.RW, Writable: m.RW,
Propagation: m.Propagation, 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) mounts = append(mounts, mnt)
} }
} }

View File

@ -402,11 +402,6 @@ func (s *DockerSuite) TestEventsFilterContainer(c *check.C) {
func (s *DockerSuite) TestEventsStreaming(c *check.C) { func (s *DockerSuite) TestEventsStreaming(c *check.C) {
testRequires(c, DaemonIsLinux) testRequires(c, DaemonIsLinux)
eventCreate := make(chan struct{})
eventStart := make(chan struct{})
eventDie := make(chan struct{})
eventDestroy := make(chan struct{})
observer, err := newEventObserver(c) observer, err := newEventObserver(c)
c.Assert(err, checker.IsNil) c.Assert(err, checker.IsNil)
err = observer.Start() err = observer.Start()
@ -415,42 +410,21 @@ func (s *DockerSuite) TestEventsStreaming(c *check.C) {
out, _ := dockerCmd(c, "run", "-d", "busybox:latest", "true") out, _ := dockerCmd(c, "run", "-d", "busybox:latest", "true")
containerID := strings.TrimSpace(out) 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) { testActions := map[string]chan bool{
switch { "create": make(chan bool),
case matchCreate.MatchString(text): "start": make(chan bool),
close(eventCreate) "die": make(chan bool),
case matchStart.MatchString(text): "destroy": make(chan bool),
close(eventStart)
case matchDie.MatchString(text):
close(eventDie)
case matchDestroy.MatchString(text):
close(eventDestroy)
}
} }
go observer.Match(matcher)
go observer.Match(matchEventLine(containerID, "container", testActions))
select { select {
case <-time.After(5 * time.Second): case <-time.After(5 * time.Second):
c.Fatal(observer.TimeoutError(containerID, "create")) c.Fatal(observer.TimeoutError(containerID, "create/start/die"))
case <-testActions["create"]: case <-testActions["create"]:
// ignore, done
}
select {
case <-time.After(5 * time.Second):
c.Fatal(observer.TimeoutError(containerID, "start"))
case <-testActions["start"]: case <-testActions["start"]:
// ignore, done
}
select {
case <-time.After(5 * time.Second):
c.Fatal(observer.TimeoutError(containerID, "die"))
case <-testActions["die"]: case <-testActions["die"]:
// ignore, done // ignore, done
} }
@ -460,7 +434,7 @@ func (s *DockerSuite) TestEventsStreaming(c *check.C) {
select { select {
case <-time.After(5 * time.Second): case <-time.After(5 * time.Second):
c.Fatal(observer.TimeoutError(containerID, "destroy")) c.Fatal(observer.TimeoutError(containerID, "destroy"))
case <-eventDestroy: case <-testActions["destroy"]:
// ignore, done // ignore, done
} }
} }

View File

@ -151,3 +151,29 @@ func (s *DockerSuite) TestEventsContainerFilterBeforeCreate(c *check.C) {
<-ch <-ch
c.Assert(out, checker.Contains, cID, check.Commentf("Missing event of container (foo)")) 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")
}

View File

@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"io" "io"
"os/exec" "os/exec"
"regexp"
"strconv" "strconv"
"strings" "strings"