Event notification message definition

This commit defines the message format used to notify external parties of
activity within a registry instance. The event includes information about which
action was taken on which registry object, including what user created the
action and which instance generated the event.

Message instances can be sent throughout an application or transmitted
externally. An envelope format along with a custom media type is defined along
with tests to detect changes to the wire format.

Signed-off-by: Stephen J Day <stephen.day@docker.com>
This commit is contained in:
Stephen J Day 2015-01-27 19:37:16 -08:00
parent 092dadde6d
commit af7eb42793
2 changed files with 253 additions and 0 deletions

View file

@ -0,0 +1,131 @@
package notifications
import (
"encoding/json"
"strings"
"testing"
"time"
)
// TestEventJSONFormat provides silly test to detect if the event format or
// envelope has changed. If this code fails, the revision of the protocol may
// need to be incremented.
func TestEventEnvelopeJSONFormat(t *testing.T) {
var expected = strings.TrimSpace(`
{
"events": [
{
"uuid": "asdf-asdf-asdf-asdf-0",
"timestamp": "2006-01-02T15:04:05Z",
"action": "push",
"target": {
"type": "manifest",
"name": "library/test",
"digest": "sha256:0123456789abcdef0",
"tag": "latest",
"url": "http://example.com/v2/library/test/manifests/latest"
},
"actor": {
"name": "test-actor",
"addr": "hostname.local"
},
"source": {
"addr": "hostname.local",
"host": "registrycluster.local",
"request_id": "asdfasdf"
}
},
{
"uuid": "asdf-asdf-asdf-asdf-1",
"timestamp": "2006-01-02T15:04:05Z",
"action": "push",
"target": {
"type": "blob",
"name": "library/test",
"digest": "tarsum.v2+sha256:0123456789abcdef1",
"url": "http://example.com/v2/library/test/manifests/latest"
},
"actor": {
"name": "test-actor",
"addr": "hostname.local"
},
"source": {
"addr": "hostname.local",
"host": "registrycluster.local",
"request_id": "asdfasdf"
}
},
{
"uuid": "asdf-asdf-asdf-asdf-2",
"timestamp": "2006-01-02T15:04:05Z",
"action": "push",
"target": {
"type": "blob",
"name": "library/test",
"digest": "tarsum.v2+sha256:0123456789abcdef2",
"url": "http://example.com/v2/library/test/manifests/latest"
},
"actor": {
"name": "test-actor",
"addr": "hostname.local"
},
"source": {
"addr": "hostname.local",
"host": "registrycluster.local",
"request_id": "asdfasdf"
}
}
]
}
`)
tm, err := time.Parse(time.RFC3339, time.RFC3339[:len(time.RFC3339)-5])
if err != nil {
t.Fatalf("error creating time: %v", err)
}
var prototype Event
prototype.Action = "push"
prototype.Timestamp = tm
prototype.Actor.Addr = "hostname.local"
prototype.Actor.Name = "test-actor"
prototype.Source.Addr = "hostname.local"
prototype.Source.Host = "registrycluster.local"
prototype.Source.RequestID = "asdfasdf"
var manifestPush Event
manifestPush = prototype
manifestPush.ID = "asdf-asdf-asdf-asdf-0"
manifestPush.Target.Digest = "sha256:0123456789abcdef0"
manifestPush.Target.Type = "manifest"
manifestPush.Target.Name = "library/test"
manifestPush.Target.Tag = "latest"
manifestPush.Target.URL = "http://example.com/v2/library/test/manifests/latest"
var layerPush0 Event
layerPush0 = prototype
layerPush0.ID = "asdf-asdf-asdf-asdf-1"
layerPush0.Target.Digest = "tarsum.v2+sha256:0123456789abcdef1"
layerPush0.Target.Type = "blob"
layerPush0.Target.Name = "library/test"
layerPush0.Target.URL = "http://example.com/v2/library/test/manifests/latest"
var layerPush1 Event
layerPush1 = prototype
layerPush1.ID = "asdf-asdf-asdf-asdf-2"
layerPush1.Target.Digest = "tarsum.v2+sha256:0123456789abcdef2"
layerPush1.Target.Type = "blob"
layerPush1.Target.Name = "library/test"
layerPush1.Target.URL = "http://example.com/v2/library/test/manifests/latest"
var envelope Envelope
envelope.Events = append(envelope.Events, manifestPush, layerPush0, layerPush1)
p, err := json.MarshalIndent(envelope, "", " ")
if err != nil {
t.Fatalf("unexpected error marshaling envelope: %v", err)
}
if string(p) != expected {
t.Fatalf("format has changed\n%s\n != \n%s", string(p), expected)
}
}