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
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)
}
}

View File

@ -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
}

View File

@ -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

View File

@ -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 {

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) {
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
}

View File

@ -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
}

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) {
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)

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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
}
}

View File

@ -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")
}

View File

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