Merge pull request #18888 from calavera/event_types
Event all the things! Upstream-commit: 723be0a3325799fd6b2a6b689af54f5a07edf992 Component: engine
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -699,6 +699,7 @@ func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName
|
||||
return derr.ErrorCodeJoinInfo.WithArgs(err)
|
||||
}
|
||||
|
||||
daemon.LogNetworkEventWithAttributes(n, "connect", map[string]string{"container": container.ID})
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -719,6 +720,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 +850,18 @@ 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
|
||||
var networks []libnetwork.Network
|
||||
for n := range settings {
|
||||
if nw, err := daemon.FindNetwork(n); err == nil {
|
||||
networks = append(networks, nw)
|
||||
}
|
||||
settings[n] = &networktypes.EndpointSettings{}
|
||||
}
|
||||
|
||||
container.NetworkSettings = &network.Settings{Networks: networks}
|
||||
container.NetworkSettings = &network.Settings{Networks: settings}
|
||||
|
||||
if sid == "" || len(networks) == 0 {
|
||||
if sid == "" || len(settings) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -864,6 +874,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 _, nw := range networks {
|
||||
daemon.LogNetworkEventWithAttributes(nw, "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
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"github.com/docker/docker/api"
|
||||
"github.com/docker/docker/api/types"
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
eventtypes "github.com/docker/docker/api/types/events"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
registrytypes "github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/api/types/strslice"
|
||||
@@ -47,7 +48,6 @@ import (
|
||||
"github.com/docker/docker/pkg/fileutils"
|
||||
"github.com/docker/docker/pkg/graphdb"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
"github.com/docker/docker/pkg/mount"
|
||||
"github.com/docker/docker/pkg/namesgenerator"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
@@ -554,23 +554,9 @@ func (daemon *Daemon) GetByName(name string) (*container.Container, error) {
|
||||
return e, nil
|
||||
}
|
||||
|
||||
// getEventFilter returns a filters.Filter for a set of filters
|
||||
func (daemon *Daemon) getEventFilter(filter filters.Args) *events.Filter {
|
||||
// incoming container filter can be name, id or partial id, convert to
|
||||
// a full container id
|
||||
for _, cn := range filter.Get("container") {
|
||||
c, err := daemon.GetContainer(cn)
|
||||
filter.Del("container", cn)
|
||||
if err == nil {
|
||||
filter.Add("container", c.ID)
|
||||
}
|
||||
}
|
||||
return events.NewFilter(filter, daemon.GetLabels)
|
||||
}
|
||||
|
||||
// SubscribeToEvents returns the currently record of events, a channel to stream new events from, and a function to cancel the stream of events.
|
||||
func (daemon *Daemon) SubscribeToEvents(since, sinceNano int64, filter filters.Args) ([]*jsonmessage.JSONMessage, chan interface{}) {
|
||||
ef := daemon.getEventFilter(filter)
|
||||
func (daemon *Daemon) SubscribeToEvents(since, sinceNano int64, filter filters.Args) ([]eventtypes.Message, chan interface{}) {
|
||||
ef := events.NewFilter(filter)
|
||||
return daemon.EventsService.SubscribeTopic(since, sinceNano, ef)
|
||||
}
|
||||
|
||||
@@ -580,21 +566,6 @@ func (daemon *Daemon) UnsubscribeFromEvents(listener chan interface{}) {
|
||||
daemon.EventsService.Evict(listener)
|
||||
}
|
||||
|
||||
// GetLabels for a container or image id
|
||||
func (daemon *Daemon) GetLabels(id string) map[string]string {
|
||||
// TODO: TestCase
|
||||
container := daemon.containers.Get(id)
|
||||
if container != nil {
|
||||
return container.Config.Labels
|
||||
}
|
||||
|
||||
img, err := daemon.GetImage(id)
|
||||
if err == nil {
|
||||
return img.ContainerConfig.Labels
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// children returns all child containers of the container with the
|
||||
// given name. The containers are returned as a map from the container
|
||||
// name to a pointer to Container.
|
||||
@@ -1032,7 +1003,8 @@ func (daemon *Daemon) TagImage(newTag reference.Named, imageName string) error {
|
||||
if err := daemon.referenceStore.AddTag(newTag, imageID, true); err != nil {
|
||||
return err
|
||||
}
|
||||
daemon.EventsService.Log("tag", newTag.String(), "")
|
||||
|
||||
daemon.LogImageEvent(imageID.String(), newTag.String(), "tag")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1068,15 +1040,15 @@ func (daemon *Daemon) PullImage(ref reference.Named, metaHeaders map[string][]st
|
||||
}()
|
||||
|
||||
imagePullConfig := &distribution.ImagePullConfig{
|
||||
MetaHeaders: metaHeaders,
|
||||
AuthConfig: authConfig,
|
||||
ProgressOutput: progress.ChanOutput(progressChan),
|
||||
RegistryService: daemon.RegistryService,
|
||||
EventsService: daemon.EventsService,
|
||||
MetadataStore: daemon.distributionMetadataStore,
|
||||
ImageStore: daemon.imageStore,
|
||||
ReferenceStore: daemon.referenceStore,
|
||||
DownloadManager: daemon.downloadManager,
|
||||
MetaHeaders: metaHeaders,
|
||||
AuthConfig: authConfig,
|
||||
ProgressOutput: progress.ChanOutput(progressChan),
|
||||
RegistryService: daemon.RegistryService,
|
||||
ImageEventLogger: daemon.LogImageEvent,
|
||||
MetadataStore: daemon.distributionMetadataStore,
|
||||
ImageStore: daemon.imageStore,
|
||||
ReferenceStore: daemon.referenceStore,
|
||||
DownloadManager: daemon.downloadManager,
|
||||
}
|
||||
|
||||
err := distribution.Pull(ctx, ref, imagePullConfig)
|
||||
@@ -1111,17 +1083,17 @@ func (daemon *Daemon) PushImage(ref reference.Named, metaHeaders map[string][]st
|
||||
}()
|
||||
|
||||
imagePushConfig := &distribution.ImagePushConfig{
|
||||
MetaHeaders: metaHeaders,
|
||||
AuthConfig: authConfig,
|
||||
ProgressOutput: progress.ChanOutput(progressChan),
|
||||
RegistryService: daemon.RegistryService,
|
||||
EventsService: daemon.EventsService,
|
||||
MetadataStore: daemon.distributionMetadataStore,
|
||||
LayerStore: daemon.layerStore,
|
||||
ImageStore: daemon.imageStore,
|
||||
ReferenceStore: daemon.referenceStore,
|
||||
TrustKey: daemon.trustKey,
|
||||
UploadManager: daemon.uploadManager,
|
||||
MetaHeaders: metaHeaders,
|
||||
AuthConfig: authConfig,
|
||||
ProgressOutput: progress.ChanOutput(progressChan),
|
||||
RegistryService: daemon.RegistryService,
|
||||
ImageEventLogger: daemon.LogImageEvent,
|
||||
MetadataStore: daemon.distributionMetadataStore,
|
||||
LayerStore: daemon.layerStore,
|
||||
ImageStore: daemon.imageStore,
|
||||
ReferenceStore: daemon.referenceStore,
|
||||
TrustKey: daemon.trustKey,
|
||||
UploadManager: daemon.uploadManager,
|
||||
}
|
||||
|
||||
err := distribution.Push(ctx, ref, imagePushConfig)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -1,14 +1,81 @@
|
||||
package daemon
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types/events"
|
||||
"github.com/docker/docker/container"
|
||||
"github.com/docker/libnetwork"
|
||||
)
|
||||
|
||||
// LogContainerEvent generates an event related to a container.
|
||||
func (daemon *Daemon) LogContainerEvent(container *container.Container, action string) {
|
||||
daemon.EventsService.Log(
|
||||
action,
|
||||
container.ID,
|
||||
container.Config.Image,
|
||||
)
|
||||
attributes := copyAttributes(container.Config.Labels)
|
||||
if container.Config.Image != "" {
|
||||
attributes["image"] = container.Config.Image
|
||||
}
|
||||
attributes["name"] = strings.TrimLeft(container.Name, "/")
|
||||
|
||||
actor := events.Actor{
|
||||
ID: container.ID,
|
||||
Attributes: attributes,
|
||||
}
|
||||
daemon.EventsService.Log(action, events.ContainerEventType, actor)
|
||||
}
|
||||
|
||||
// LogImageEvent generates an event related to a container.
|
||||
func (daemon *Daemon) LogImageEvent(imageID, refName, action string) {
|
||||
attributes := map[string]string{}
|
||||
img, err := daemon.GetImage(imageID)
|
||||
if err == nil && img.Config != nil {
|
||||
// image has not been removed yet.
|
||||
// it could be missing if the event is `delete`.
|
||||
attributes = copyAttributes(img.Config.Labels)
|
||||
}
|
||||
if refName != "" {
|
||||
attributes["name"] = refName
|
||||
}
|
||||
actor := events.Actor{
|
||||
ID: imageID,
|
||||
Attributes: attributes,
|
||||
}
|
||||
|
||||
daemon.EventsService.Log(action, events.ImageEventType, actor)
|
||||
}
|
||||
|
||||
// LogVolumeEvent generates an event related to a volume.
|
||||
func (daemon *Daemon) LogVolumeEvent(volumeID, action string, attributes map[string]string) {
|
||||
actor := events.Actor{
|
||||
ID: volumeID,
|
||||
Attributes: attributes,
|
||||
}
|
||||
daemon.EventsService.Log(action, events.VolumeEventType, actor)
|
||||
}
|
||||
|
||||
// LogNetworkEvent generates an event related to a network with only the default attributes.
|
||||
func (daemon *Daemon) LogNetworkEvent(nw libnetwork.Network, action string) {
|
||||
daemon.LogNetworkEventWithAttributes(nw, action, map[string]string{})
|
||||
}
|
||||
|
||||
// LogNetworkEventWithAttributes generates an event related to a network with specific given attributes.
|
||||
func (daemon *Daemon) LogNetworkEventWithAttributes(nw libnetwork.Network, action string, attributes map[string]string) {
|
||||
attributes["name"] = nw.Name()
|
||||
attributes["type"] = nw.Type()
|
||||
actor := events.Actor{
|
||||
ID: nw.ID(),
|
||||
Attributes: attributes,
|
||||
}
|
||||
daemon.EventsService.Log(action, events.NetworkEventType, actor)
|
||||
}
|
||||
|
||||
// copyAttributes guarantees that labels are not mutated by event triggers.
|
||||
func copyAttributes(labels map[string]string) map[string]string {
|
||||
attributes := map[string]string{}
|
||||
if labels == nil {
|
||||
return attributes
|
||||
}
|
||||
for k, v := range labels {
|
||||
attributes[k] = v
|
||||
}
|
||||
return attributes
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
eventtypes "github.com/docker/docker/api/types/events"
|
||||
"github.com/docker/docker/pkg/pubsub"
|
||||
)
|
||||
|
||||
@@ -13,17 +13,17 @@ const (
|
||||
bufferSize = 1024
|
||||
)
|
||||
|
||||
// Events is pubsub channel for *jsonmessage.JSONMessage
|
||||
// Events is pubsub channel for events generated by the engine.
|
||||
type Events struct {
|
||||
mu sync.Mutex
|
||||
events []*jsonmessage.JSONMessage
|
||||
events []eventtypes.Message
|
||||
pub *pubsub.Publisher
|
||||
}
|
||||
|
||||
// New returns new *Events instance
|
||||
func New() *Events {
|
||||
return &Events{
|
||||
events: make([]*jsonmessage.JSONMessage, 0, eventsLimit),
|
||||
events: make([]eventtypes.Message, 0, eventsLimit),
|
||||
pub: pubsub.NewPublisher(100*time.Millisecond, bufferSize),
|
||||
}
|
||||
}
|
||||
@@ -32,9 +32,9 @@ func New() *Events {
|
||||
// last events, a channel in which you can expect new events (in form
|
||||
// of interface{}, so you need type assertion), and a function to call
|
||||
// to stop the stream of events.
|
||||
func (e *Events) Subscribe() ([]*jsonmessage.JSONMessage, chan interface{}, func()) {
|
||||
func (e *Events) Subscribe() ([]eventtypes.Message, chan interface{}, func()) {
|
||||
e.mu.Lock()
|
||||
current := make([]*jsonmessage.JSONMessage, len(e.events))
|
||||
current := make([]eventtypes.Message, len(e.events))
|
||||
copy(current, e.events)
|
||||
l := e.pub.Subscribe()
|
||||
e.mu.Unlock()
|
||||
@@ -48,13 +48,13 @@ func (e *Events) Subscribe() ([]*jsonmessage.JSONMessage, chan interface{}, func
|
||||
// SubscribeTopic adds new listener to events, returns slice of 64 stored
|
||||
// last events, a channel in which you can expect new events (in form
|
||||
// of interface{}, so you need type assertion).
|
||||
func (e *Events) SubscribeTopic(since, sinceNano int64, ef *Filter) ([]*jsonmessage.JSONMessage, chan interface{}) {
|
||||
func (e *Events) SubscribeTopic(since, sinceNano int64, ef *Filter) ([]eventtypes.Message, chan interface{}) {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
|
||||
var buffered []*jsonmessage.JSONMessage
|
||||
var buffered []eventtypes.Message
|
||||
topic := func(m interface{}) bool {
|
||||
return ef.Include(m.(*jsonmessage.JSONMessage))
|
||||
return ef.Include(m.(eventtypes.Message))
|
||||
}
|
||||
|
||||
if since != -1 {
|
||||
@@ -64,7 +64,7 @@ func (e *Events) SubscribeTopic(since, sinceNano int64, ef *Filter) ([]*jsonmess
|
||||
break
|
||||
}
|
||||
if ef.filter.Len() == 0 || topic(ev) {
|
||||
buffered = append([]*jsonmessage.JSONMessage{ev}, buffered...)
|
||||
buffered = append([]eventtypes.Message{ev}, buffered...)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,9 +87,27 @@ func (e *Events) Evict(l chan interface{}) {
|
||||
|
||||
// Log broadcasts event to listeners. Each listener has 100 millisecond for
|
||||
// receiving event or it will be skipped.
|
||||
func (e *Events) Log(action, id, from string) {
|
||||
func (e *Events) Log(action, eventType string, actor eventtypes.Actor) {
|
||||
now := time.Now().UTC()
|
||||
jm := &jsonmessage.JSONMessage{Status: action, ID: id, From: from, Time: now.Unix(), TimeNano: now.UnixNano()}
|
||||
jm := eventtypes.Message{
|
||||
Action: action,
|
||||
Type: eventType,
|
||||
Actor: actor,
|
||||
Time: now.Unix(),
|
||||
TimeNano: now.UnixNano(),
|
||||
}
|
||||
|
||||
// fill deprecated fields for container and images
|
||||
switch eventType {
|
||||
case eventtypes.ContainerEventType:
|
||||
jm.ID = actor.ID
|
||||
jm.Status = action
|
||||
jm.From = actor.Attributes["image"]
|
||||
case eventtypes.ImageEventType:
|
||||
jm.ID = actor.ID
|
||||
jm.Status = action
|
||||
}
|
||||
|
||||
e.mu.Lock()
|
||||
if len(e.events) == cap(e.events) {
|
||||
// discard oldest event
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
"github.com/docker/docker/api/types/events"
|
||||
)
|
||||
|
||||
func TestEventsLog(t *testing.T) {
|
||||
@@ -18,10 +18,14 @@ func TestEventsLog(t *testing.T) {
|
||||
if count != 2 {
|
||||
t.Fatalf("Must be 2 subscribers, got %d", count)
|
||||
}
|
||||
e.Log("test", "cont", "image")
|
||||
actor := events.Actor{
|
||||
ID: "cont",
|
||||
Attributes: map[string]string{"image": "image"},
|
||||
}
|
||||
e.Log("test", events.ContainerEventType, actor)
|
||||
select {
|
||||
case msg := <-l1:
|
||||
jmsg, ok := msg.(*jsonmessage.JSONMessage)
|
||||
jmsg, ok := msg.(events.Message)
|
||||
if !ok {
|
||||
t.Fatalf("Unexpected type %T", msg)
|
||||
}
|
||||
@@ -42,7 +46,7 @@ func TestEventsLog(t *testing.T) {
|
||||
}
|
||||
select {
|
||||
case msg := <-l2:
|
||||
jmsg, ok := msg.(*jsonmessage.JSONMessage)
|
||||
jmsg, ok := msg.(events.Message)
|
||||
if !ok {
|
||||
t.Fatalf("Unexpected type %T", msg)
|
||||
}
|
||||
@@ -70,7 +74,10 @@ func TestEventsLogTimeout(t *testing.T) {
|
||||
|
||||
c := make(chan struct{})
|
||||
go func() {
|
||||
e.Log("test", "cont", "image")
|
||||
actor := events.Actor{
|
||||
ID: "image",
|
||||
}
|
||||
e.Log("test", events.ImageEventType, actor)
|
||||
close(c)
|
||||
}()
|
||||
|
||||
@@ -88,7 +95,12 @@ func TestLogEvents(t *testing.T) {
|
||||
action := fmt.Sprintf("action_%d", i)
|
||||
id := fmt.Sprintf("cont_%d", i)
|
||||
from := fmt.Sprintf("image_%d", i)
|
||||
e.Log(action, id, from)
|
||||
|
||||
actor := events.Actor{
|
||||
ID: id,
|
||||
Attributes: map[string]string{"image": from},
|
||||
}
|
||||
e.Log(action, events.ContainerEventType, actor)
|
||||
}
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
current, l, _ := e.Subscribe()
|
||||
@@ -97,16 +109,21 @@ func TestLogEvents(t *testing.T) {
|
||||
action := fmt.Sprintf("action_%d", num)
|
||||
id := fmt.Sprintf("cont_%d", num)
|
||||
from := fmt.Sprintf("image_%d", num)
|
||||
e.Log(action, id, from)
|
||||
|
||||
actor := events.Actor{
|
||||
ID: id,
|
||||
Attributes: map[string]string{"image": from},
|
||||
}
|
||||
e.Log(action, events.ContainerEventType, actor)
|
||||
}
|
||||
if len(e.events) != eventsLimit {
|
||||
t.Fatalf("Must be %d events, got %d", eventsLimit, len(e.events))
|
||||
}
|
||||
|
||||
var msgs []*jsonmessage.JSONMessage
|
||||
var msgs []events.Message
|
||||
for len(msgs) < 10 {
|
||||
m := <-l
|
||||
jm, ok := (m).(*jsonmessage.JSONMessage)
|
||||
jm, ok := (m).(events.Message)
|
||||
if !ok {
|
||||
t.Fatalf("Unexpected type %T", m)
|
||||
}
|
||||
|
||||
@@ -1,46 +1,76 @@
|
||||
package events
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/api/types/events"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
// Filter can filter out docker events from a stream
|
||||
type Filter struct {
|
||||
filter filters.Args
|
||||
getLabels func(id string) map[string]string
|
||||
filter filters.Args
|
||||
}
|
||||
|
||||
// NewFilter creates a new Filter
|
||||
func NewFilter(filter filters.Args, getLabels func(id string) map[string]string) *Filter {
|
||||
return &Filter{filter: filter, getLabels: getLabels}
|
||||
func NewFilter(filter filters.Args) *Filter {
|
||||
return &Filter{filter: filter}
|
||||
}
|
||||
|
||||
// Include returns true when the event ev is included by the filters
|
||||
func (ef *Filter) Include(ev *jsonmessage.JSONMessage) bool {
|
||||
return ef.filter.ExactMatch("event", ev.Status) &&
|
||||
ef.filter.ExactMatch("container", ev.ID) &&
|
||||
ef.isImageIncluded(ev.ID, ev.From) &&
|
||||
ef.isLabelFieldIncluded(ev.ID)
|
||||
func (ef *Filter) Include(ev events.Message) bool {
|
||||
return ef.filter.ExactMatch("event", ev.Action) &&
|
||||
ef.filter.ExactMatch("type", ev.Type) &&
|
||||
ef.matchContainer(ev) &&
|
||||
ef.matchVolume(ev) &&
|
||||
ef.matchNetwork(ev) &&
|
||||
ef.matchImage(ev) &&
|
||||
ef.matchLabels(ev.Actor.Attributes)
|
||||
}
|
||||
|
||||
func (ef *Filter) isLabelFieldIncluded(id string) bool {
|
||||
func (ef *Filter) matchLabels(attributes map[string]string) bool {
|
||||
if !ef.filter.Include("label") {
|
||||
return true
|
||||
}
|
||||
return ef.filter.MatchKVList("label", ef.getLabels(id))
|
||||
return ef.filter.MatchKVList("label", attributes)
|
||||
}
|
||||
|
||||
// The image filter will be matched against both event.ID (for image events)
|
||||
// and event.From (for container events), so that any container that was created
|
||||
func (ef *Filter) matchContainer(ev events.Message) bool {
|
||||
return ef.fuzzyMatchName(ev, events.ContainerEventType)
|
||||
}
|
||||
|
||||
func (ef *Filter) matchVolume(ev events.Message) bool {
|
||||
return ef.fuzzyMatchName(ev, events.VolumeEventType)
|
||||
}
|
||||
|
||||
func (ef *Filter) matchNetwork(ev events.Message) bool {
|
||||
return ef.fuzzyMatchName(ev, events.NetworkEventType)
|
||||
}
|
||||
|
||||
func (ef *Filter) fuzzyMatchName(ev events.Message, eventType string) bool {
|
||||
return ef.filter.FuzzyMatch(eventType, ev.Actor.ID) ||
|
||||
ef.filter.FuzzyMatch(eventType, ev.Actor.Attributes["name"])
|
||||
}
|
||||
|
||||
// matchImage matches against both event.Actor.ID (for image events)
|
||||
// and event.Actor.Attributes["image"] (for container events), so that any container that was created
|
||||
// from an image will be included in the image events. Also compare both
|
||||
// against the stripped repo name without any tags.
|
||||
func (ef *Filter) isImageIncluded(eventID string, eventFrom string) bool {
|
||||
return ef.filter.ExactMatch("image", eventID) ||
|
||||
ef.filter.ExactMatch("image", eventFrom) ||
|
||||
ef.filter.ExactMatch("image", stripTag(eventID)) ||
|
||||
ef.filter.ExactMatch("image", stripTag(eventFrom))
|
||||
func (ef *Filter) matchImage(ev events.Message) bool {
|
||||
id := ev.Actor.ID
|
||||
nameAttr := "image"
|
||||
var imageName string
|
||||
|
||||
if ev.Type == events.ImageEventType {
|
||||
nameAttr = "name"
|
||||
}
|
||||
|
||||
if n, ok := ev.Actor.Attributes[nameAttr]; ok {
|
||||
imageName = n
|
||||
}
|
||||
return ef.filter.ExactMatch("image", id) ||
|
||||
ef.filter.ExactMatch("image", imageName) ||
|
||||
ef.filter.ExactMatch("image", stripTag(id)) ||
|
||||
ef.filter.ExactMatch("image", stripTag(imageName))
|
||||
}
|
||||
|
||||
func stripTag(image string) string {
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package daemon
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/container"
|
||||
"github.com/docker/docker/daemon/events"
|
||||
)
|
||||
|
||||
func TestLogContainerCopyLabels(t *testing.T) {
|
||||
e := events.New()
|
||||
_, l, _ := e.Subscribe()
|
||||
defer e.Evict(l)
|
||||
|
||||
container := &container.Container{
|
||||
CommonContainer: container.CommonContainer{
|
||||
ID: "container_id",
|
||||
Name: "container_name",
|
||||
Config: &containertypes.Config{
|
||||
Labels: map[string]string{
|
||||
"node": "1",
|
||||
"os": "alpine",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
daemon := &Daemon{
|
||||
EventsService: e,
|
||||
}
|
||||
daemon.LogContainerEvent(container, "create")
|
||||
|
||||
if _, mutated := container.Config.Labels["image"]; mutated {
|
||||
t.Fatalf("Expected to not mutate the container labels, got %q", container.Config.Labels)
|
||||
}
|
||||
}
|
||||
@@ -87,7 +87,7 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
|
||||
|
||||
untaggedRecord := types.ImageDelete{Untagged: parsedRef.String()}
|
||||
|
||||
daemon.EventsService.Log("untag", imgID.String(), "")
|
||||
daemon.LogImageEvent(imgID.String(), imgID.String(), "untag")
|
||||
records = append(records, untaggedRecord)
|
||||
|
||||
// If has remaining references then untag finishes the remove
|
||||
@@ -109,7 +109,7 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
|
||||
|
||||
untaggedRecord := types.ImageDelete{Untagged: parsedRef.String()}
|
||||
|
||||
daemon.EventsService.Log("untag", imgID.String(), "")
|
||||
daemon.LogImageEvent(imgID.String(), imgID.String(), "untag")
|
||||
records = append(records, untaggedRecord)
|
||||
}
|
||||
}
|
||||
@@ -174,7 +174,7 @@ func (daemon *Daemon) removeAllReferencesToImageID(imgID image.ID, records *[]ty
|
||||
|
||||
untaggedRecord := types.ImageDelete{Untagged: parsedRef.String()}
|
||||
|
||||
daemon.EventsService.Log("untag", imgID.String(), "")
|
||||
daemon.LogImageEvent(imgID.String(), imgID.String(), "untag")
|
||||
*records = append(*records, untaggedRecord)
|
||||
}
|
||||
|
||||
@@ -243,7 +243,7 @@ func (daemon *Daemon) imageDeleteHelper(imgID image.ID, records *[]types.ImageDe
|
||||
return err
|
||||
}
|
||||
|
||||
daemon.EventsService.Log("delete", imgID.String(), "")
|
||||
daemon.LogImageEvent(imgID.String(), imgID.String(), "delete")
|
||||
*records = append(*records, types.ImageDelete{Deleted: imgID.String()})
|
||||
for _, removedLayer := range removedLayers {
|
||||
*records = append(*records, types.ImageDelete{Deleted: removedLayer.ChainID.String()})
|
||||
|
||||
@@ -97,7 +97,7 @@ func (daemon *Daemon) ImportImage(src string, newRef reference.Named, msg string
|
||||
}
|
||||
}
|
||||
|
||||
daemon.EventsService.Log("import", id.String(), "")
|
||||
daemon.LogImageEvent(id.String(), id.String(), "import")
|
||||
outStream.Write(sf.FormatStatus("", id.String()))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types/network"
|
||||
derr "github.com/docker/docker/errors"
|
||||
"github.com/docker/docker/runconfig"
|
||||
"github.com/docker/libnetwork"
|
||||
)
|
||||
|
||||
@@ -114,7 +116,13 @@ func (daemon *Daemon) CreateNetwork(name, driver string, ipam network.IPAM, opti
|
||||
|
||||
nwOptions = append(nwOptions, libnetwork.NetworkOptionIpam(ipam.Driver, "", v4Conf, v6Conf))
|
||||
nwOptions = append(nwOptions, libnetwork.NetworkOptionDriverOpts(options))
|
||||
return c.NewNetwork(driver, name, nwOptions...)
|
||||
n, err := c.NewNetwork(driver, name, nwOptions...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
daemon.LogNetworkEvent(n, "create")
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func getIpamConfig(data []network.IPAMConfig) ([]*libnetwork.IpamConf, []*libnetwork.IpamConf, error) {
|
||||
@@ -178,3 +186,21 @@ func (daemon *Daemon) GetNetworkDriverList() map[string]bool {
|
||||
|
||||
return pluginList
|
||||
}
|
||||
|
||||
// DeleteNetwork destroys a network unless it's one of docker's predefined networks.
|
||||
func (daemon *Daemon) DeleteNetwork(networkID string) error {
|
||||
nw, err := daemon.FindNetwork(networkID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if runconfig.IsPreDefinedNetwork(nw.Name()) {
|
||||
return derr.ErrorCodeCantDeletePredefinedNetwork.WithArgs(nw.Name())
|
||||
}
|
||||
|
||||
if err := nw.Delete(); err != nil {
|
||||
return err
|
||||
}
|
||||
daemon.LogNetworkEvent(nw, "destroy")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,5 +54,7 @@ func (daemon *Daemon) update(name string, hostConfig *container.HostConfig) erro
|
||||
}
|
||||
}
|
||||
|
||||
daemon.LogContainerEvent(container, "update")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user