diff --git a/notifications/bridge.go b/notifications/bridge.go index 93a2362a..efaa3ac3 100644 --- a/notifications/bridge.go +++ b/notifications/bridge.go @@ -72,6 +72,15 @@ func (b *bridge) BlobPulled(repo string, desc distribution.Descriptor) error { return b.createBlobEventAndWrite(EventActionPull, repo, desc) } +func (b *bridge) BlobMounted(repo string, desc distribution.Descriptor, fromRepo string) error { + event, err := b.createBlobEvent(EventActionMount, repo, desc) + if err != nil { + return err + } + event.Target.FromRepository = fromRepo + return b.sink.Write(*event) +} + func (b *bridge) BlobDeleted(repo string, desc distribution.Descriptor) error { return b.createBlobEventAndWrite(EventActionDelete, repo, desc) } diff --git a/notifications/event.go b/notifications/event.go index 97030026..19d6a776 100644 --- a/notifications/event.go +++ b/notifications/event.go @@ -11,6 +11,7 @@ import ( const ( EventActionPull = "pull" EventActionPush = "push" + EventActionMount = "mount" EventActionDelete = "delete" ) @@ -61,6 +62,10 @@ type Event struct { // Repository identifies the named repository. Repository string `json:"repository,omitempty"` + // FromRepository identifies the named repository which a blob was mounted + // from if appropriate. + FromRepository string `json:"fromRepository,omitempty"` + // URL provides a direct link to the content. URL string `json:"url,omitempty"` } `json:"target,omitempty"` diff --git a/notifications/listener.go b/notifications/listener.go index baecbdbd..d4e1abe7 100644 --- a/notifications/listener.go +++ b/notifications/listener.go @@ -24,6 +24,7 @@ type ManifestListener interface { type BlobListener interface { BlobPushed(repo string, desc distribution.Descriptor) error BlobPulled(repo string, desc distribution.Descriptor) error + BlobMounted(repo string, desc distribution.Descriptor, fromRepo string) error // TODO(stevvooe): Please note that delete support is still a little shaky // and we'll need to propagate these in the future. @@ -169,6 +170,17 @@ func (bsl *blobServiceListener) Resume(ctx context.Context, id string) (distribu return bsl.decorateWriter(wr), err } +func (bsl *blobServiceListener) Mount(ctx context.Context, sourceRepo string, dgst digest.Digest) (distribution.Descriptor, error) { + desc, err := bsl.BlobStore.Mount(ctx, sourceRepo, dgst) + if err == nil { + if err := bsl.parent.listener.BlobMounted(bsl.parent.Repository.Name(), desc, sourceRepo); err != nil { + context.GetLogger(ctx).Errorf("error dispatching layer mount to listener: %v", err) + } + } + + return desc, err +} + func (bsl *blobServiceListener) decorateWriter(wr distribution.BlobWriter) distribution.BlobWriter { return &blobWriterListener{ BlobWriter: wr, diff --git a/notifications/listener_test.go b/notifications/listener_test.go index 319406c3..17ffa288 100644 --- a/notifications/listener_test.go +++ b/notifications/listener_test.go @@ -81,6 +81,11 @@ func (tl *testListener) BlobPulled(repo string, desc distribution.Descriptor) er return nil } +func (tl *testListener) BlobMounted(repo string, desc distribution.Descriptor, fromRepo string) error { + tl.ops["layer:mount"]++ + return nil +} + func (tl *testListener) BlobDeleted(repo string, desc distribution.Descriptor) error { tl.ops["layer:delete"]++ return nil