Merge pull request #239 from jlhawn/event_target_update
notifications: update notification event Target fields
This commit is contained in:
commit
f0ccdd448f
6 changed files with 89 additions and 55 deletions
|
@ -65,37 +65,38 @@ func (b *bridge) ManifestDeleted(repo distribution.Repository, sm *manifest.Sign
|
|||
}
|
||||
|
||||
func (b *bridge) LayerPushed(repo distribution.Repository, layer distribution.Layer) error {
|
||||
return b.createLayerEventAndWrite(EventActionPush, repo, layer.Digest())
|
||||
return b.createLayerEventAndWrite(EventActionPush, repo, layer)
|
||||
}
|
||||
|
||||
func (b *bridge) LayerPulled(repo distribution.Repository, layer distribution.Layer) error {
|
||||
return b.createLayerEventAndWrite(EventActionPull, repo, layer.Digest())
|
||||
return b.createLayerEventAndWrite(EventActionPull, repo, layer)
|
||||
}
|
||||
|
||||
func (b *bridge) LayerDeleted(repo distribution.Repository, layer distribution.Layer) error {
|
||||
return b.createLayerEventAndWrite(EventActionDelete, repo, layer.Digest())
|
||||
return b.createLayerEventAndWrite(EventActionDelete, repo, layer)
|
||||
}
|
||||
|
||||
func (b *bridge) createManifestEventAndWrite(action string, repo distribution.Repository, sm *manifest.SignedManifest) error {
|
||||
event, err := b.createManifestEvent(action, repo, sm)
|
||||
manifestEvent, err := b.createManifestEvent(action, repo, sm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return b.sink.Write(*event)
|
||||
return b.sink.Write(*manifestEvent)
|
||||
}
|
||||
|
||||
func (b *bridge) createManifestEvent(action string, repo distribution.Repository, sm *manifest.SignedManifest) (*Event, error) {
|
||||
event := b.createEvent(action)
|
||||
event.Target.Type = EventTargetTypeManifest
|
||||
event.Target.Name = repo.Name()
|
||||
event.Target.Tag = sm.Tag
|
||||
event.Target.MediaType = manifest.ManifestMediaType
|
||||
event.Target.Repository = repo.Name()
|
||||
|
||||
p, err := sm.Payload()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
event.Target.Length = int64(len(p))
|
||||
|
||||
event.Target.Digest, err = digest.FromBytes(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -111,8 +112,8 @@ func (b *bridge) createManifestEvent(action string, repo distribution.Repository
|
|||
return event, nil
|
||||
}
|
||||
|
||||
func (b *bridge) createLayerEventAndWrite(action string, repo distribution.Repository, dgst digest.Digest) error {
|
||||
event, err := b.createLayerEvent(action, repo, dgst)
|
||||
func (b *bridge) createLayerEventAndWrite(action string, repo distribution.Repository, layer distribution.Layer) error {
|
||||
event, err := b.createLayerEvent(action, repo, layer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -120,10 +121,14 @@ func (b *bridge) createLayerEventAndWrite(action string, repo distribution.Repos
|
|||
return b.sink.Write(*event)
|
||||
}
|
||||
|
||||
func (b *bridge) createLayerEvent(action string, repo distribution.Repository, dgst digest.Digest) (*Event, error) {
|
||||
func (b *bridge) createLayerEvent(action string, repo distribution.Repository, layer distribution.Layer) (*Event, error) {
|
||||
event := b.createEvent(action)
|
||||
event.Target.Type = EventTargetTypeBlob
|
||||
event.Target.Name = repo.Name()
|
||||
event.Target.MediaType = layerMediaType
|
||||
event.Target.Repository = repo.Name()
|
||||
|
||||
event.Target.Length = layer.Length()
|
||||
|
||||
dgst := layer.Digest()
|
||||
event.Target.Digest = dgst
|
||||
|
||||
var err error
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution"
|
||||
)
|
||||
|
||||
// EventAction constants used in action field of Event.
|
||||
|
@ -14,17 +14,16 @@ const (
|
|||
EventActionDelete = "delete"
|
||||
)
|
||||
|
||||
// EventTargetType constants used in Target section of Event.
|
||||
const (
|
||||
EventTargetTypeManifest = "manifest"
|
||||
EventTargetTypeBlob = "blob"
|
||||
// EventsMediaType is the mediatype for the json event envelope. If the
|
||||
// Event, ActorRecord, SourceRecord or Envelope structs change, the version
|
||||
// number should be incremented.
|
||||
EventsMediaType = "application/vnd.docker.distribution.events.v1+json"
|
||||
// LayerMediaType is the media type for image rootfs diffs (aka "layers")
|
||||
// used by Docker. We don't expect this to change for quite a while.
|
||||
layerMediaType = "application/vnd.docker.container.image.rootfs.diff+x-gtar"
|
||||
)
|
||||
|
||||
// EventsMediaType is the mediatype for the json event envelope. If the Event,
|
||||
// ActorRecord, SourceRecord or Envelope structs change, the version number
|
||||
// should be incremented.
|
||||
const EventsMediaType = "application/vnd.docker.distribution.events.v1+json"
|
||||
|
||||
// Envelope defines the fields of a json event envelope message that can hold
|
||||
// one or more events.
|
||||
type Envelope struct {
|
||||
|
@ -51,19 +50,14 @@ type Event struct {
|
|||
|
||||
// Target uniquely describes the target of the event.
|
||||
Target struct {
|
||||
// Type should be "manifest" or "blob"
|
||||
Type string `json:"type,omitempty"`
|
||||
// TODO(stevvooe): Use http.DetectContentType for layers, maybe.
|
||||
|
||||
// Name identifies the named repository.
|
||||
Name string `json:"name,omitempty"`
|
||||
distribution.Descriptor
|
||||
|
||||
// Digest should identify the object in the repository.
|
||||
Digest digest.Digest `json:"digest,omitempty"`
|
||||
// Repository identifies the named repository.
|
||||
Repository string `json:"repository,omitempty"`
|
||||
|
||||
// Tag is present if the operation involved a tagged manifest.
|
||||
Tag string `json:"tag,omitempty"`
|
||||
|
||||
// URL provides a link to the content on the relevant repository instance.
|
||||
// URL provides a direct link to the content.
|
||||
URL string `json:"url,omitempty"`
|
||||
} `json:"target,omitempty"`
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution/manifest"
|
||||
)
|
||||
|
||||
// TestEventJSONFormat provides silly test to detect if the event format or
|
||||
|
@ -19,10 +21,10 @@ func TestEventEnvelopeJSONFormat(t *testing.T) {
|
|||
"timestamp": "2006-01-02T15:04:05Z",
|
||||
"action": "push",
|
||||
"target": {
|
||||
"type": "manifest",
|
||||
"name": "library/test",
|
||||
"mediaType": "application/vnd.docker.distribution.manifest.v1+json",
|
||||
"length": 1,
|
||||
"digest": "sha256:0123456789abcdef0",
|
||||
"tag": "latest",
|
||||
"repository": "library/test",
|
||||
"url": "http://example.com/v2/library/test/manifests/latest"
|
||||
},
|
||||
"request": {
|
||||
|
@ -44,9 +46,10 @@ func TestEventEnvelopeJSONFormat(t *testing.T) {
|
|||
"timestamp": "2006-01-02T15:04:05Z",
|
||||
"action": "push",
|
||||
"target": {
|
||||
"type": "blob",
|
||||
"name": "library/test",
|
||||
"mediaType": "application/vnd.docker.container.image.rootfs.diff+x-gtar",
|
||||
"length": 2,
|
||||
"digest": "tarsum.v2+sha256:0123456789abcdef1",
|
||||
"repository": "library/test",
|
||||
"url": "http://example.com/v2/library/test/manifests/latest"
|
||||
},
|
||||
"request": {
|
||||
|
@ -68,9 +71,10 @@ func TestEventEnvelopeJSONFormat(t *testing.T) {
|
|||
"timestamp": "2006-01-02T15:04:05Z",
|
||||
"action": "push",
|
||||
"target": {
|
||||
"type": "blob",
|
||||
"name": "library/test",
|
||||
"mediaType": "application/vnd.docker.container.image.rootfs.diff+x-gtar",
|
||||
"length": 3,
|
||||
"digest": "tarsum.v2+sha256:0123456789abcdef2",
|
||||
"repository": "library/test",
|
||||
"url": "http://example.com/v2/library/test/manifests/latest"
|
||||
},
|
||||
"request": {
|
||||
|
@ -97,7 +101,7 @@ func TestEventEnvelopeJSONFormat(t *testing.T) {
|
|||
}
|
||||
|
||||
var prototype Event
|
||||
prototype.Action = "push"
|
||||
prototype.Action = EventActionPush
|
||||
prototype.Timestamp = tm
|
||||
prototype.Actor.Name = "test-actor"
|
||||
prototype.Request.ID = "asdfasdf"
|
||||
|
@ -111,25 +115,27 @@ func TestEventEnvelopeJSONFormat(t *testing.T) {
|
|||
manifestPush = prototype
|
||||
manifestPush.ID = "asdf-asdf-asdf-asdf-0"
|
||||
manifestPush.Target.Digest = "sha256:0123456789abcdef0"
|
||||
manifestPush.Target.Type = EventTargetTypeManifest
|
||||
manifestPush.Target.Name = "library/test"
|
||||
manifestPush.Target.Tag = "latest"
|
||||
manifestPush.Target.Length = int64(1)
|
||||
manifestPush.Target.MediaType = manifest.ManifestMediaType
|
||||
manifestPush.Target.Repository = "library/test"
|
||||
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 = EventTargetTypeBlob
|
||||
layerPush0.Target.Name = "library/test"
|
||||
layerPush0.Target.Length = 2
|
||||
layerPush0.Target.MediaType = layerMediaType
|
||||
layerPush0.Target.Repository = "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 = EventTargetTypeBlob
|
||||
layerPush1.Target.Name = "library/test"
|
||||
layerPush1.Target.Length = 3
|
||||
layerPush1.Target.MediaType = layerMediaType
|
||||
layerPush1.Target.Repository = "library/test"
|
||||
layerPush1.Target.URL = "http://example.com/v2/library/test/manifests/latest"
|
||||
|
||||
var envelope Envelope
|
||||
|
|
|
@ -9,6 +9,8 @@ import (
|
|||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/distribution/manifest"
|
||||
)
|
||||
|
||||
// TestHTTPSink mocks out an http endpoint and notifies it under a couple of
|
||||
|
@ -73,14 +75,14 @@ func TestHTTPSink(t *testing.T) {
|
|||
{
|
||||
statusCode: http.StatusOK,
|
||||
events: []Event{
|
||||
createTestEvent("push", "library/test", "manifest")},
|
||||
createTestEvent("push", "library/test", manifest.ManifestMediaType)},
|
||||
},
|
||||
{
|
||||
statusCode: http.StatusOK,
|
||||
events: []Event{
|
||||
createTestEvent("push", "library/test", "manifest"),
|
||||
createTestEvent("push", "library/test", "layer"),
|
||||
createTestEvent("push", "library/test", "layer"),
|
||||
createTestEvent("push", "library/test", manifest.ManifestMediaType),
|
||||
createTestEvent("push", "library/test", layerMediaType),
|
||||
createTestEvent("push", "library/test", layerMediaType),
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -148,8 +150,8 @@ func TestHTTPSink(t *testing.T) {
|
|||
func createTestEvent(action, repo, typ string) Event {
|
||||
event := createEvent(action)
|
||||
|
||||
event.Target.Type = typ
|
||||
event.Target.Name = repo
|
||||
event.Target.MediaType = typ
|
||||
event.Target.Repository = repo
|
||||
|
||||
return *event
|
||||
}
|
||||
|
|
27
registry.go
27
registry.go
|
@ -98,10 +98,12 @@ type Layer interface {
|
|||
io.ReadSeeker
|
||||
io.Closer
|
||||
|
||||
// Digest returns the unique digest of the blob, which is the tarsum for
|
||||
// layers.
|
||||
// Digest returns the unique digest of the blob.
|
||||
Digest() digest.Digest
|
||||
|
||||
// Length returns the length in bytes of the blob.
|
||||
Length() int64
|
||||
|
||||
// CreatedAt returns the time this layer was created.
|
||||
CreatedAt() time.Time
|
||||
}
|
||||
|
@ -137,3 +139,24 @@ type SignatureService interface {
|
|||
// Put stores the signature for the provided digest.
|
||||
Put(dgst digest.Digest, signatures ...[]byte) error
|
||||
}
|
||||
|
||||
// Descriptor describes targeted content. Used in conjunction with a blob
|
||||
// store, a descriptor can be used to fetch, store and target any kind of
|
||||
// blob. The struct also describes the wire protocol format. Fields should
|
||||
// only be added but never changed.
|
||||
type Descriptor struct {
|
||||
// MediaType describe the type of the content. All text based formats are
|
||||
// encoded as utf-8.
|
||||
MediaType string `json:"mediaType,omitempty"`
|
||||
|
||||
// Length in bytes of content.
|
||||
Length int64 `json:"length,omitempty"`
|
||||
|
||||
// Digest uniquely identifies the content. A byte stream can be verified
|
||||
// against against this digest.
|
||||
Digest digest.Digest `json:"digest,omitempty"`
|
||||
|
||||
// NOTE: Before adding a field here, please ensure that all
|
||||
// other options have been exhausted. Much of the type relationships
|
||||
// depend on the simplicity of this type.
|
||||
}
|
||||
|
|
|
@ -21,6 +21,10 @@ func (lrs *layerReader) Digest() digest.Digest {
|
|||
return lrs.digest
|
||||
}
|
||||
|
||||
func (lrs *layerReader) Length() int64 {
|
||||
return lrs.size
|
||||
}
|
||||
|
||||
func (lrs *layerReader) CreatedAt() time.Time {
|
||||
return lrs.modtime
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue