40273b1d36
This changeset implements immutable manifest references via the HTTP API. Most of the changes follow from modifications to ManifestService. Once updates were made across the repo to implement these changes, the http handlers were change accordingly. The new methods on ManifestService will be broken out into a tagging service in a later PR. Unfortunately, due to complexities around managing the manifest tag index in an eventually consistent manner, direct deletes of manifests have been disabled. Signed-off-by: Stephen J Day <stephen.day@docker.com>
152 lines
4.3 KiB
Go
152 lines
4.3 KiB
Go
package notifications
|
|
|
|
import (
|
|
"github.com/Sirupsen/logrus"
|
|
"github.com/docker/distribution"
|
|
"github.com/docker/distribution/digest"
|
|
"github.com/docker/distribution/manifest"
|
|
)
|
|
|
|
// ManifestListener describes a set of methods for listening to events related to manifests.
|
|
type ManifestListener interface {
|
|
ManifestPushed(repo distribution.Repository, sm *manifest.SignedManifest) error
|
|
ManifestPulled(repo distribution.Repository, sm *manifest.SignedManifest) error
|
|
|
|
// TODO(stevvooe): Please note that delete support is still a little shaky
|
|
// and we'll need to propagate these in the future.
|
|
|
|
ManifestDeleted(repo distribution.Repository, sm *manifest.SignedManifest) error
|
|
}
|
|
|
|
// LayerListener describes a listener that can respond to layer related events.
|
|
type LayerListener interface {
|
|
LayerPushed(repo distribution.Repository, layer distribution.Layer) error
|
|
LayerPulled(repo distribution.Repository, layer distribution.Layer) error
|
|
|
|
// TODO(stevvooe): Please note that delete support is still a little shaky
|
|
// and we'll need to propagate these in the future.
|
|
|
|
LayerDeleted(repo distribution.Repository, layer distribution.Layer) error
|
|
}
|
|
|
|
// Listener combines all repository events into a single interface.
|
|
type Listener interface {
|
|
ManifestListener
|
|
LayerListener
|
|
}
|
|
|
|
type repositoryListener struct {
|
|
distribution.Repository
|
|
listener Listener
|
|
}
|
|
|
|
// Listen dispatches events on the repository to the listener.
|
|
func Listen(repo distribution.Repository, listener Listener) distribution.Repository {
|
|
return &repositoryListener{
|
|
Repository: repo,
|
|
listener: listener,
|
|
}
|
|
}
|
|
|
|
func (rl *repositoryListener) Manifests() distribution.ManifestService {
|
|
return &manifestServiceListener{
|
|
ManifestService: rl.Repository.Manifests(),
|
|
parent: rl,
|
|
}
|
|
}
|
|
|
|
func (rl *repositoryListener) Layers() distribution.LayerService {
|
|
return &layerServiceListener{
|
|
LayerService: rl.Repository.Layers(),
|
|
parent: rl,
|
|
}
|
|
}
|
|
|
|
type manifestServiceListener struct {
|
|
distribution.ManifestService
|
|
parent *repositoryListener
|
|
}
|
|
|
|
func (msl *manifestServiceListener) Get(dgst digest.Digest) (*manifest.SignedManifest, error) {
|
|
sm, err := msl.ManifestService.Get(dgst)
|
|
if err == nil {
|
|
if err := msl.parent.listener.ManifestPulled(msl.parent.Repository, sm); err != nil {
|
|
logrus.Errorf("error dispatching manifest pull to listener: %v", err)
|
|
}
|
|
}
|
|
|
|
return sm, err
|
|
}
|
|
|
|
func (msl *manifestServiceListener) Put(sm *manifest.SignedManifest) error {
|
|
err := msl.ManifestService.Put(sm)
|
|
|
|
if err == nil {
|
|
if err := msl.parent.listener.ManifestPushed(msl.parent.Repository, sm); err != nil {
|
|
logrus.Errorf("error dispatching manifest push to listener: %v", err)
|
|
}
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
func (msl *manifestServiceListener) GetByTag(tag string) (*manifest.SignedManifest, error) {
|
|
sm, err := msl.ManifestService.GetByTag(tag)
|
|
if err == nil {
|
|
if err := msl.parent.listener.ManifestPulled(msl.parent.Repository, sm); err != nil {
|
|
logrus.Errorf("error dispatching manifest pull to listener: %v", err)
|
|
}
|
|
}
|
|
|
|
return sm, err
|
|
}
|
|
|
|
type layerServiceListener struct {
|
|
distribution.LayerService
|
|
parent *repositoryListener
|
|
}
|
|
|
|
func (lsl *layerServiceListener) Fetch(dgst digest.Digest) (distribution.Layer, error) {
|
|
layer, err := lsl.LayerService.Fetch(dgst)
|
|
if err == nil {
|
|
if err := lsl.parent.listener.LayerPulled(lsl.parent.Repository, layer); err != nil {
|
|
logrus.Errorf("error dispatching layer pull to listener: %v", err)
|
|
}
|
|
}
|
|
|
|
return layer, err
|
|
}
|
|
|
|
func (lsl *layerServiceListener) Upload() (distribution.LayerUpload, error) {
|
|
lu, err := lsl.LayerService.Upload()
|
|
return lsl.decorateUpload(lu), err
|
|
}
|
|
|
|
func (lsl *layerServiceListener) Resume(uuid string) (distribution.LayerUpload, error) {
|
|
lu, err := lsl.LayerService.Resume(uuid)
|
|
return lsl.decorateUpload(lu), err
|
|
}
|
|
|
|
func (lsl *layerServiceListener) decorateUpload(lu distribution.LayerUpload) distribution.LayerUpload {
|
|
return &layerUploadListener{
|
|
LayerUpload: lu,
|
|
parent: lsl,
|
|
}
|
|
}
|
|
|
|
type layerUploadListener struct {
|
|
distribution.LayerUpload
|
|
parent *layerServiceListener
|
|
}
|
|
|
|
func (lul *layerUploadListener) Finish(dgst digest.Digest) (distribution.Layer, error) {
|
|
layer, err := lul.LayerUpload.Finish(dgst)
|
|
if err == nil {
|
|
if err := lul.parent.parent.listener.LayerPushed(lul.parent.parent.Repository, layer); err != nil {
|
|
logrus.Errorf("error dispatching layer push to listener: %v", err)
|
|
}
|
|
}
|
|
|
|
return layer, err
|
|
}
|