Skip to content

Commit 72f1881

Browse files
committed
Add event types.
- Stop serializing JSONMessage in favor of events.Message. - Keep backwards compatibility with JSONMessage for container events. Signed-off-by: David Calavera <[email protected]>
1 parent 687ef00 commit 72f1881

23 files changed

Lines changed: 666 additions & 318 deletions

api/client/events.go

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
package client
22

33
import (
4+
"encoding/json"
5+
"fmt"
6+
"io"
7+
"strings"
8+
"time"
9+
410
"github.com/docker/docker/api/types"
11+
eventtypes "github.com/docker/docker/api/types/events"
512
"github.com/docker/docker/api/types/filters"
613
Cli "github.com/docker/docker/cli"
714
"github.com/docker/docker/opts"
8-
"github.com/docker/docker/pkg/jsonmessage"
15+
"github.com/docker/docker/pkg/jsonlog"
916
flag "github.com/docker/docker/pkg/mflag"
1017
)
1118

@@ -46,5 +53,43 @@ func (cli *DockerCli) CmdEvents(args ...string) error {
4653
}
4754
defer responseBody.Close()
4855

49-
return jsonmessage.DisplayJSONMessagesStream(responseBody, cli.out, cli.outFd, cli.isTerminalOut)
56+
return streamEvents(responseBody, cli.out)
57+
}
58+
59+
// streamEvents decodes prints the incoming events in the provided output.
60+
func streamEvents(input io.Reader, output io.Writer) error {
61+
dec := json.NewDecoder(input)
62+
for {
63+
var event eventtypes.Message
64+
if err := dec.Decode(&event); err != nil {
65+
if err == io.EOF {
66+
break
67+
}
68+
return err
69+
}
70+
printOutput(event, output)
71+
}
72+
return nil
73+
}
74+
75+
// printOutput prints all types of event information.
76+
// Each output includes the event type, actor id, name and action.
77+
// Actor attributes are printed at the end if the actor has any.
78+
func printOutput(event eventtypes.Message, output io.Writer) {
79+
if event.TimeNano != 0 {
80+
fmt.Fprintf(output, "%s ", time.Unix(0, event.TimeNano).Format(jsonlog.RFC3339NanoFixed))
81+
} else if event.Time != 0 {
82+
fmt.Fprintf(output, "%s ", time.Unix(event.Time, 0).Format(jsonlog.RFC3339NanoFixed))
83+
}
84+
85+
fmt.Fprintf(output, "%s %s %s", event.Type, event.Action, event.Actor.ID)
86+
87+
if len(event.Actor.Attributes) > 0 {
88+
var attrs []string
89+
for k, v := range event.Actor.Attributes {
90+
attrs = append(attrs, fmt.Sprintf("%s=%s", k, v))
91+
}
92+
fmt.Fprintf(output, " (%s)", strings.Join(attrs, ", "))
93+
}
94+
fmt.Fprint(output, "\n")
5095
}

api/server/router/system/backend.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,16 @@ package system
22

33
import (
44
"github.com/docker/docker/api/types"
5+
"github.com/docker/docker/api/types/events"
56
"github.com/docker/docker/api/types/filters"
6-
"github.com/docker/docker/pkg/jsonmessage"
77
)
88

99
// Backend is the methods that need to be implemented to provide
1010
// system specific functionality.
1111
type Backend interface {
1212
SystemInfo() (*types.Info, error)
1313
SystemVersion() types.Version
14-
SubscribeToEvents(since, sinceNano int64, ef filters.Args) ([]*jsonmessage.JSONMessage, chan interface{})
14+
SubscribeToEvents(since, sinceNano int64, ef filters.Args) ([]events.Message, chan interface{})
1515
UnsubscribeFromEvents(chan interface{})
1616
AuthenticateToRegistry(authConfig *types.AuthConfig) (string, error)
1717
}

api/server/router/system/system_routes.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ import (
99
"github.com/docker/docker/api"
1010
"github.com/docker/docker/api/server/httputils"
1111
"github.com/docker/docker/api/types"
12+
"github.com/docker/docker/api/types/events"
1213
"github.com/docker/docker/api/types/filters"
1314
timetypes "github.com/docker/docker/api/types/time"
1415
"github.com/docker/docker/pkg/ioutils"
15-
"github.com/docker/docker/pkg/jsonmessage"
1616
"golang.org/x/net/context"
1717
)
1818

@@ -98,8 +98,9 @@ func (s *systemRouter) getEvents(ctx context.Context, w http.ResponseWriter, r *
9898
for {
9999
select {
100100
case ev := <-l:
101-
jev, ok := ev.(*jsonmessage.JSONMessage)
101+
jev, ok := ev.(events.Message)
102102
if !ok {
103+
logrus.Warnf("unexpected event message: %q", ev)
103104
continue
104105
}
105106
if err := enc.Encode(jev); err != nil {

api/types/events/events.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package events
2+
3+
const (
4+
// ContainerEventType is the event type that containers generate
5+
ContainerEventType = "container"
6+
// ImageEventType is the event type that images generate
7+
ImageEventType = "image"
8+
// VolumeEventType is the event type that volumes generate
9+
VolumeEventType = "volume"
10+
// NetworkEventType is the event type that networks generate
11+
NetworkEventType = "network"
12+
)
13+
14+
// Actor describes something that generates events,
15+
// like a container, or a network, or a volume.
16+
// It has a defined name and a set or attributes.
17+
// The container attributes are its labels, other actors
18+
// can generate these attributes from other properties.
19+
type Actor struct {
20+
ID string
21+
Attributes map[string]string
22+
}
23+
24+
// Message represents the information an event contains
25+
type Message struct {
26+
// Deprecated information from JSONMessage.
27+
// With data only in container events.
28+
Status string `json:"status,omitempty"`
29+
ID string `json:"id,omitempty"`
30+
From string `json:"from,omitempty"`
31+
32+
Type string
33+
Action string
34+
Actor Actor
35+
36+
Time int64 `json:"time,omitempty"`
37+
TimeNano int64 `json:"timeNano,omitempty"`
38+
}

api/types/filters/parse.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,22 @@ func (filters Args) ExactMatch(field, source string) bool {
197197
return false
198198
}
199199

200+
// FuzzyMatch returns true if the source matches exactly one of the filters,
201+
// or the source has one of the filters as a prefix.
202+
func (filters Args) FuzzyMatch(field, source string) bool {
203+
if filters.ExactMatch(field, source) {
204+
return true
205+
}
206+
207+
fieldValues := filters.fields[field]
208+
for prefix := range fieldValues {
209+
if strings.HasPrefix(source, prefix) {
210+
return true
211+
}
212+
}
213+
return false
214+
}
215+
200216
// Include returns true if the name of the field to filter is in the filters.
201217
func (filters Args) Include(field string) bool {
202218
_, ok := filters.fields[field]

api/types/filters/parse_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,3 +349,21 @@ func TestWalkValues(t *testing.T) {
349349
t.Fatalf("Expected to not iterate when the field doesn't exist, got %v", err)
350350
}
351351
}
352+
353+
func TestFuzzyMatch(t *testing.T) {
354+
f := NewArgs()
355+
f.Add("container", "foo")
356+
357+
cases := map[string]bool{
358+
"foo": true,
359+
"foobar": true,
360+
"barfoo": false,
361+
"bar": false,
362+
}
363+
for source, match := range cases {
364+
got := f.FuzzyMatch("container", source)
365+
if got != match {
366+
t.Fatalf("Expected %v, got %v: %s", match, got, source)
367+
}
368+
}
369+
}

daemon/daemon.go

Lines changed: 25 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/docker/docker/api"
2323
"github.com/docker/docker/api/types"
2424
containertypes "github.com/docker/docker/api/types/container"
25+
eventtypes "github.com/docker/docker/api/types/events"
2526
"github.com/docker/docker/api/types/filters"
2627
registrytypes "github.com/docker/docker/api/types/registry"
2728
"github.com/docker/docker/api/types/strslice"
@@ -47,7 +48,6 @@ import (
4748
"github.com/docker/docker/pkg/fileutils"
4849
"github.com/docker/docker/pkg/graphdb"
4950
"github.com/docker/docker/pkg/idtools"
50-
"github.com/docker/docker/pkg/jsonmessage"
5151
"github.com/docker/docker/pkg/mount"
5252
"github.com/docker/docker/pkg/namesgenerator"
5353
"github.com/docker/docker/pkg/progress"
@@ -554,23 +554,9 @@ func (daemon *Daemon) GetByName(name string) (*container.Container, error) {
554554
return e, nil
555555
}
556556

557-
// getEventFilter returns a filters.Filter for a set of filters
558-
func (daemon *Daemon) getEventFilter(filter filters.Args) *events.Filter {
559-
// incoming container filter can be name, id or partial id, convert to
560-
// a full container id
561-
for _, cn := range filter.Get("container") {
562-
c, err := daemon.GetContainer(cn)
563-
filter.Del("container", cn)
564-
if err == nil {
565-
filter.Add("container", c.ID)
566-
}
567-
}
568-
return events.NewFilter(filter, daemon.GetLabels)
569-
}
570-
571557
// SubscribeToEvents returns the currently record of events, a channel to stream new events from, and a function to cancel the stream of events.
572-
func (daemon *Daemon) SubscribeToEvents(since, sinceNano int64, filter filters.Args) ([]*jsonmessage.JSONMessage, chan interface{}) {
573-
ef := daemon.getEventFilter(filter)
558+
func (daemon *Daemon) SubscribeToEvents(since, sinceNano int64, filter filters.Args) ([]eventtypes.Message, chan interface{}) {
559+
ef := events.NewFilter(filter)
574560
return daemon.EventsService.SubscribeTopic(since, sinceNano, ef)
575561
}
576562

@@ -580,21 +566,6 @@ func (daemon *Daemon) UnsubscribeFromEvents(listener chan interface{}) {
580566
daemon.EventsService.Evict(listener)
581567
}
582568

583-
// GetLabels for a container or image id
584-
func (daemon *Daemon) GetLabels(id string) map[string]string {
585-
// TODO: TestCase
586-
container := daemon.containers.Get(id)
587-
if container != nil {
588-
return container.Config.Labels
589-
}
590-
591-
img, err := daemon.GetImage(id)
592-
if err == nil {
593-
return img.ContainerConfig.Labels
594-
}
595-
return nil
596-
}
597-
598569
// children returns all child containers of the container with the
599570
// given name. The containers are returned as a map from the container
600571
// name to a pointer to Container.
@@ -1032,7 +1003,8 @@ func (daemon *Daemon) TagImage(newTag reference.Named, imageName string) error {
10321003
if err := daemon.referenceStore.AddTag(newTag, imageID, true); err != nil {
10331004
return err
10341005
}
1035-
daemon.EventsService.Log("tag", newTag.String(), "")
1006+
1007+
daemon.LogImageEvent(imageID.String(), newTag.String(), "tag")
10361008
return nil
10371009
}
10381010

@@ -1068,15 +1040,15 @@ func (daemon *Daemon) PullImage(ref reference.Named, metaHeaders map[string][]st
10681040
}()
10691041

10701042
imagePullConfig := &distribution.ImagePullConfig{
1071-
MetaHeaders: metaHeaders,
1072-
AuthConfig: authConfig,
1073-
ProgressOutput: progress.ChanOutput(progressChan),
1074-
RegistryService: daemon.RegistryService,
1075-
EventsService: daemon.EventsService,
1076-
MetadataStore: daemon.distributionMetadataStore,
1077-
ImageStore: daemon.imageStore,
1078-
ReferenceStore: daemon.referenceStore,
1079-
DownloadManager: daemon.downloadManager,
1043+
MetaHeaders: metaHeaders,
1044+
AuthConfig: authConfig,
1045+
ProgressOutput: progress.ChanOutput(progressChan),
1046+
RegistryService: daemon.RegistryService,
1047+
ImageEventLogger: daemon.LogImageEvent,
1048+
MetadataStore: daemon.distributionMetadataStore,
1049+
ImageStore: daemon.imageStore,
1050+
ReferenceStore: daemon.referenceStore,
1051+
DownloadManager: daemon.downloadManager,
10801052
}
10811053

10821054
err := distribution.Pull(ctx, ref, imagePullConfig)
@@ -1111,17 +1083,17 @@ func (daemon *Daemon) PushImage(ref reference.Named, metaHeaders map[string][]st
11111083
}()
11121084

11131085
imagePushConfig := &distribution.ImagePushConfig{
1114-
MetaHeaders: metaHeaders,
1115-
AuthConfig: authConfig,
1116-
ProgressOutput: progress.ChanOutput(progressChan),
1117-
RegistryService: daemon.RegistryService,
1118-
EventsService: daemon.EventsService,
1119-
MetadataStore: daemon.distributionMetadataStore,
1120-
LayerStore: daemon.layerStore,
1121-
ImageStore: daemon.imageStore,
1122-
ReferenceStore: daemon.referenceStore,
1123-
TrustKey: daemon.trustKey,
1124-
UploadManager: daemon.uploadManager,
1086+
MetaHeaders: metaHeaders,
1087+
AuthConfig: authConfig,
1088+
ProgressOutput: progress.ChanOutput(progressChan),
1089+
RegistryService: daemon.RegistryService,
1090+
ImageEventLogger: daemon.LogImageEvent,
1091+
MetadataStore: daemon.distributionMetadataStore,
1092+
LayerStore: daemon.layerStore,
1093+
ImageStore: daemon.imageStore,
1094+
ReferenceStore: daemon.referenceStore,
1095+
TrustKey: daemon.trustKey,
1096+
UploadManager: daemon.uploadManager,
11251097
}
11261098

11271099
err := distribution.Push(ctx, ref, imagePushConfig)

0 commit comments

Comments
 (0)