Move layer interface definitions to distribution package
After consideration, it has been decided that the interfaces defined in the storage package provide a good base for interacting with various registry instances. Whether interacting with a remote API or a local, on-disk registry, these types have proved flexible. By moving them here, they can become the central components of interacting with distribution components. Signed-off-by: Stephen J Day <stephen.day@docker.com>
This commit is contained in:
parent
5a0f1ceeef
commit
553d48d618
20 changed files with 113 additions and 265 deletions
|
@ -7,8 +7,10 @@ import (
|
|||
"os"
|
||||
|
||||
"code.google.com/p/go-uuid/uuid"
|
||||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/configuration"
|
||||
ctxu "github.com/docker/distribution/context"
|
||||
"github.com/docker/distribution/notifications"
|
||||
"github.com/docker/distribution/registry/api/v2"
|
||||
"github.com/docker/distribution/registry/auth"
|
||||
"github.com/docker/distribution/registry/storage"
|
||||
|
@ -32,7 +34,7 @@ type App struct {
|
|||
|
||||
router *mux.Router // main application router, configured with dispatchers
|
||||
driver storagedriver.StorageDriver // driver maintains the app global storage driver instance.
|
||||
registry storage.Registry // registry is the primary registry backend for the app instance.
|
||||
registry distribution.Registry // registry is the primary registry backend for the app instance.
|
||||
accessController auth.AccessController // main access controller for application
|
||||
|
||||
// events contains notification related configuration.
|
||||
|
|
|
@ -4,10 +4,10 @@ import (
|
|||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/distribution"
|
||||
ctxu "github.com/docker/distribution/context"
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/registry/api/v2"
|
||||
"github.com/docker/distribution/registry/storage"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
|
@ -21,7 +21,7 @@ type Context struct {
|
|||
|
||||
// Repository is the repository for the current request. All requests
|
||||
// should be scoped to a single repository. This field may be nil.
|
||||
Repository storage.Repository
|
||||
Repository distribution.Repository
|
||||
|
||||
// Errors is a collection of errors encountered during the request to be
|
||||
// returned to the client API. If errors are added to the collection, the
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/distribution"
|
||||
ctxu "github.com/docker/distribution/context"
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/manifest"
|
||||
|
@ -72,7 +73,7 @@ func (imh *imageManifestHandler) PutImageManifest(w http.ResponseWriter, r *http
|
|||
case storage.ErrManifestVerification:
|
||||
for _, verificationError := range err {
|
||||
switch verificationError := verificationError.(type) {
|
||||
case storage.ErrUnknownLayer:
|
||||
case distribution.ErrUnknownLayer:
|
||||
imh.Errors.Push(v2.ErrorCodeBlobUnknown, verificationError.FSLayer)
|
||||
case storage.ErrManifestUnverified:
|
||||
imh.Errors.Push(v2.ErrorCodeManifestUnverified)
|
||||
|
|
|
@ -3,10 +3,10 @@ package handlers
|
|||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/distribution"
|
||||
ctxu "github.com/docker/distribution/context"
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/registry/api/v2"
|
||||
"github.com/docker/distribution/registry/storage"
|
||||
"github.com/gorilla/handlers"
|
||||
)
|
||||
|
||||
|
@ -54,7 +54,7 @@ func (lh *layerHandler) GetLayer(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
if err != nil {
|
||||
switch err := err.(type) {
|
||||
case storage.ErrUnknownLayer:
|
||||
case distribution.ErrUnknownLayer:
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
lh.Errors.Push(v2.ErrorCodeBlobUnknown, err.FSLayer)
|
||||
default:
|
||||
|
|
|
@ -7,10 +7,10 @@ import (
|
|||
"net/url"
|
||||
"os"
|
||||
|
||||
"github.com/docker/distribution"
|
||||
ctxu "github.com/docker/distribution/context"
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/registry/api/v2"
|
||||
"github.com/docker/distribution/registry/storage"
|
||||
"github.com/gorilla/handlers"
|
||||
)
|
||||
|
||||
|
@ -63,7 +63,7 @@ func layerUploadDispatcher(ctx *Context, r *http.Request) http.Handler {
|
|||
upload, err := layers.Resume(luh.UUID)
|
||||
if err != nil {
|
||||
ctxu.GetLogger(ctx).Errorf("error resolving upload: %v", err)
|
||||
if err == storage.ErrLayerUploadUnknown {
|
||||
if err == distribution.ErrLayerUploadUnknown {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
luh.Errors.Push(v2.ErrorCodeBlobUploadUnknown, err)
|
||||
|
@ -114,7 +114,7 @@ type layerUploadHandler struct {
|
|||
// UUID identifies the upload instance for the current request.
|
||||
UUID string
|
||||
|
||||
Upload storage.LayerUpload
|
||||
Upload distribution.LayerUpload
|
||||
|
||||
State layerUploadState
|
||||
}
|
||||
|
@ -196,7 +196,7 @@ func (luh *layerUploadHandler) PutLayerUploadComplete(w http.ResponseWriter, r *
|
|||
layer, err := luh.Upload.Finish(dgst)
|
||||
if err != nil {
|
||||
switch err := err.(type) {
|
||||
case storage.ErrLayerInvalidDigest:
|
||||
case distribution.ErrLayerInvalidDigest:
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
luh.Errors.Push(v2.ErrorCodeDigestInvalid, err)
|
||||
default:
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/AdRoll/goamz/cloudfront"
|
||||
"github.com/docker/distribution"
|
||||
storagedriver "github.com/docker/distribution/registry/storage/driver"
|
||||
)
|
||||
|
||||
|
@ -95,7 +96,7 @@ func newCloudFrontLayerHandler(storageDriver storagedriver.StorageDriver, option
|
|||
|
||||
// Resolve returns an http.Handler which can serve the contents of the given
|
||||
// Layer, or an error if not supported by the storagedriver.
|
||||
func (lh *cloudFrontLayerHandler) Resolve(layer Layer) (http.Handler, error) {
|
||||
func (lh *cloudFrontLayerHandler) Resolve(layer distribution.Layer) (http.Handler, error) {
|
||||
layerURLStr, err := lh.delegateLayerHandler.urlFor(layer, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution"
|
||||
storagedriver "github.com/docker/distribution/registry/storage/driver"
|
||||
)
|
||||
|
||||
|
@ -40,7 +41,7 @@ func newDelegateLayerHandler(storageDriver storagedriver.StorageDriver, options
|
|||
|
||||
// Resolve returns an http.Handler which can serve the contents of the given
|
||||
// Layer, or an error if not supported by the storagedriver.
|
||||
func (lh *delegateLayerHandler) Resolve(layer Layer) (http.Handler, error) {
|
||||
func (lh *delegateLayerHandler) Resolve(layer distribution.Layer) (http.Handler, error) {
|
||||
// TODO(bbland): This is just a sanity check to ensure that the
|
||||
// storagedriver supports url generation. It would be nice if we didn't have
|
||||
// to do this twice for non-GET requests.
|
||||
|
@ -64,7 +65,7 @@ func (lh *delegateLayerHandler) Resolve(layer Layer) (http.Handler, error) {
|
|||
|
||||
// urlFor returns a download URL for the given layer, or the empty string if
|
||||
// unsupported.
|
||||
func (lh *delegateLayerHandler) urlFor(layer Layer, options map[string]interface{}) (string, error) {
|
||||
func (lh *delegateLayerHandler) urlFor(layer distribution.Layer, options map[string]interface{}) (string, error) {
|
||||
// Crack open the layer to get at the layerStore
|
||||
layerRd, ok := layer.(*layerReader)
|
||||
if !ok {
|
||||
|
|
|
@ -125,23 +125,8 @@ func (fr *fileReader) Seek(offset int64, whence int) (int64, error) {
|
|||
return fr.offset, err
|
||||
}
|
||||
|
||||
// Close the layer. Should be called when the resource is no longer needed.
|
||||
func (fr *fileReader) Close() error {
|
||||
if fr.err != nil {
|
||||
return fr.err
|
||||
}
|
||||
|
||||
fr.err = ErrLayerClosed
|
||||
|
||||
// close and release reader chain
|
||||
if fr.rc != nil {
|
||||
fr.rc.Close()
|
||||
}
|
||||
|
||||
fr.rc = nil
|
||||
fr.brd = nil
|
||||
|
||||
return fr.err
|
||||
return fr.closeWithErr(fmt.Errorf("fileReader: closed"))
|
||||
}
|
||||
|
||||
// reader prepares the current reader at the lrs offset, ensuring its buffered
|
||||
|
@ -199,3 +184,21 @@ func (fr *fileReader) reset() {
|
|||
fr.rc = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (fr *fileReader) closeWithErr(err error) error {
|
||||
if fr.err != nil {
|
||||
return fr.err
|
||||
}
|
||||
|
||||
fr.err = err
|
||||
|
||||
// close and release reader chain
|
||||
if fr.rc != nil {
|
||||
fr.rc.Close()
|
||||
}
|
||||
|
||||
fr.rc = nil
|
||||
fr.brd = nil
|
||||
|
||||
return fr.err
|
||||
}
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/manifest"
|
||||
)
|
||||
|
||||
// Layer provides a readable and seekable layer object. Typically,
|
||||
// implementations are *not* goroutine safe.
|
||||
type Layer interface {
|
||||
// http.ServeContent requires an efficient implementation of
|
||||
// ReadSeeker.Seek(0, os.SEEK_END).
|
||||
io.ReadSeeker
|
||||
io.Closer
|
||||
|
||||
// Name returns the repository under which this layer is linked.
|
||||
Name() string // TODO(stevvooe): struggling with nomenclature: should this be "repo" or "name"?
|
||||
|
||||
// Digest returns the unique digest of the blob, which is the tarsum for
|
||||
// layers.
|
||||
Digest() digest.Digest
|
||||
|
||||
// CreatedAt returns the time this layer was created.
|
||||
CreatedAt() time.Time
|
||||
}
|
||||
|
||||
// LayerUpload provides a handle for working with in-progress uploads.
|
||||
// Instances can be obtained from the LayerService.Upload and
|
||||
// LayerService.Resume.
|
||||
type LayerUpload interface {
|
||||
io.WriteSeeker
|
||||
io.ReaderFrom
|
||||
io.Closer
|
||||
|
||||
// Name of the repository under which the layer will be linked.
|
||||
Name() string
|
||||
|
||||
// UUID returns the identifier for this upload.
|
||||
UUID() string
|
||||
|
||||
// StartedAt returns the time this layer upload was started.
|
||||
StartedAt() time.Time
|
||||
|
||||
// Finish marks the upload as completed, returning a valid handle to the
|
||||
// uploaded layer. The digest is validated against the contents of the
|
||||
// uploaded layer.
|
||||
Finish(digest digest.Digest) (Layer, error)
|
||||
|
||||
// Cancel the layer upload process.
|
||||
Cancel() error
|
||||
}
|
||||
|
||||
var (
|
||||
// ErrLayerExists returned when layer already exists
|
||||
ErrLayerExists = fmt.Errorf("layer exists")
|
||||
|
||||
// ErrLayerTarSumVersionUnsupported when tarsum is unsupported version.
|
||||
ErrLayerTarSumVersionUnsupported = fmt.Errorf("unsupported tarsum version")
|
||||
|
||||
// ErrLayerUploadUnknown returned when upload is not found.
|
||||
ErrLayerUploadUnknown = fmt.Errorf("layer upload unknown")
|
||||
|
||||
// ErrLayerClosed returned when an operation is attempted on a closed
|
||||
// Layer or LayerUpload.
|
||||
ErrLayerClosed = fmt.Errorf("layer closed")
|
||||
)
|
||||
|
||||
// ErrUnknownLayer returned when layer cannot be found.
|
||||
type ErrUnknownLayer struct {
|
||||
FSLayer manifest.FSLayer
|
||||
}
|
||||
|
||||
func (err ErrUnknownLayer) Error() string {
|
||||
return fmt.Sprintf("unknown layer %v", err.FSLayer.BlobSum)
|
||||
}
|
||||
|
||||
// ErrLayerInvalidDigest returned when tarsum check fails.
|
||||
type ErrLayerInvalidDigest struct {
|
||||
Digest digest.Digest
|
||||
Reason error
|
||||
}
|
||||
|
||||
func (err ErrLayerInvalidDigest) Error() string {
|
||||
return fmt.Sprintf("invalid digest for referenced layer: %v, %v",
|
||||
err.Digest, err.Reason)
|
||||
}
|
|
@ -9,6 +9,7 @@ import (
|
|||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/digest"
|
||||
storagedriver "github.com/docker/distribution/registry/storage/driver"
|
||||
"github.com/docker/distribution/registry/storage/driver/inmemory"
|
||||
|
@ -53,7 +54,7 @@ func TestSimpleLayerUpload(t *testing.T) {
|
|||
|
||||
// Do a resume, get unknown upload
|
||||
layerUpload, err = ls.Resume(layerUpload.UUID())
|
||||
if err != ErrLayerUploadUnknown {
|
||||
if err != distribution.ErrLayerUploadUnknown {
|
||||
t.Fatalf("unexpected error resuming upload, should be unkown: %v", err)
|
||||
}
|
||||
|
||||
|
@ -102,7 +103,7 @@ func TestSimpleLayerUpload(t *testing.T) {
|
|||
}
|
||||
|
||||
// After finishing an upload, it should no longer exist.
|
||||
if _, err := ls.Resume(layerUpload.UUID()); err != ErrLayerUploadUnknown {
|
||||
if _, err := ls.Resume(layerUpload.UUID()); err != distribution.ErrLayerUploadUnknown {
|
||||
t.Fatalf("expected layer upload to be unknown, got %v", err)
|
||||
}
|
||||
|
||||
|
@ -165,7 +166,7 @@ func TestSimpleLayerRead(t *testing.T) {
|
|||
}
|
||||
|
||||
switch err.(type) {
|
||||
case ErrUnknownLayer:
|
||||
case distribution.ErrUnknownLayer:
|
||||
err = nil
|
||||
default:
|
||||
t.Fatalf("unexpected error fetching non-existent layer: %v", err)
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/distribution"
|
||||
storagedriver "github.com/docker/distribution/registry/storage/driver"
|
||||
)
|
||||
|
||||
|
@ -13,7 +14,7 @@ type LayerHandler interface {
|
|||
// Layer if possible, or nil and an error when unsupported. This may
|
||||
// directly serve the contents of the layer or issue a redirect to another
|
||||
// URL hosting the content.
|
||||
Resolve(layer Layer) (http.Handler, error)
|
||||
Resolve(layer distribution.Layer) (http.Handler, error)
|
||||
}
|
||||
|
||||
// LayerHandlerInitFunc is the type of a LayerHandler factory function and is
|
||||
|
|
|
@ -3,6 +3,7 @@ package storage
|
|||
import (
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/digest"
|
||||
)
|
||||
|
||||
|
@ -15,7 +16,7 @@ type layerReader struct {
|
|||
digest digest.Digest
|
||||
}
|
||||
|
||||
var _ Layer = &layerReader{}
|
||||
var _ distribution.Layer = &layerReader{}
|
||||
|
||||
func (lrs *layerReader) Name() string {
|
||||
return lrs.name
|
||||
|
@ -28,3 +29,8 @@ func (lrs *layerReader) Digest() digest.Digest {
|
|||
func (lrs *layerReader) CreatedAt() time.Time {
|
||||
return lrs.modtime
|
||||
}
|
||||
|
||||
// Close the layer. Should be called when the resource is no longer needed.
|
||||
func (lrs *layerReader) Close() error {
|
||||
return lrs.closeWithErr(distribution.ErrLayerClosed)
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"time"
|
||||
|
||||
"code.google.com/p/go-uuid/uuid"
|
||||
"github.com/docker/distribution"
|
||||
ctxu "github.com/docker/distribution/context"
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/manifest"
|
||||
|
@ -23,7 +24,7 @@ func (ls *layerStore) Exists(digest digest.Digest) (bool, error) {
|
|||
|
||||
if err != nil {
|
||||
switch err.(type) {
|
||||
case ErrUnknownLayer:
|
||||
case distribution.ErrUnknownLayer:
|
||||
return false, nil
|
||||
}
|
||||
|
||||
|
@ -33,7 +34,7 @@ func (ls *layerStore) Exists(digest digest.Digest) (bool, error) {
|
|||
return true, nil
|
||||
}
|
||||
|
||||
func (ls *layerStore) Fetch(dgst digest.Digest) (Layer, error) {
|
||||
func (ls *layerStore) Fetch(dgst digest.Digest) (distribution.Layer, error) {
|
||||
ctxu.GetLogger(ls.repository.ctx).Debug("(*layerStore).Fetch")
|
||||
bp, err := ls.path(dgst)
|
||||
if err != nil {
|
||||
|
@ -55,7 +56,7 @@ func (ls *layerStore) Fetch(dgst digest.Digest) (Layer, error) {
|
|||
// Upload begins a layer upload, returning a handle. If the layer upload
|
||||
// is already in progress or the layer has already been uploaded, this
|
||||
// will return an error.
|
||||
func (ls *layerStore) Upload() (LayerUpload, error) {
|
||||
func (ls *layerStore) Upload() (distribution.LayerUpload, error) {
|
||||
ctxu.GetLogger(ls.repository.ctx).Debug("(*layerStore).Upload")
|
||||
|
||||
// NOTE(stevvooe): Consider the issues with allowing concurrent upload of
|
||||
|
@ -93,7 +94,7 @@ func (ls *layerStore) Upload() (LayerUpload, error) {
|
|||
|
||||
// Resume continues an in progress layer upload, returning the current
|
||||
// state of the upload.
|
||||
func (ls *layerStore) Resume(uuid string) (LayerUpload, error) {
|
||||
func (ls *layerStore) Resume(uuid string) (distribution.LayerUpload, error) {
|
||||
ctxu.GetLogger(ls.repository.ctx).Debug("(*layerStore).Resume")
|
||||
startedAtPath, err := ls.repository.registry.pm.path(uploadStartedAtPathSpec{
|
||||
name: ls.repository.Name(),
|
||||
|
@ -108,7 +109,7 @@ func (ls *layerStore) Resume(uuid string) (LayerUpload, error) {
|
|||
if err != nil {
|
||||
switch err := err.(type) {
|
||||
case storagedriver.PathNotFoundError:
|
||||
return nil, ErrLayerUploadUnknown
|
||||
return nil, distribution.ErrLayerUploadUnknown
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
|
@ -132,7 +133,7 @@ func (ls *layerStore) Resume(uuid string) (LayerUpload, error) {
|
|||
}
|
||||
|
||||
// newLayerUpload allocates a new upload controller with the given state.
|
||||
func (ls *layerStore) newLayerUpload(uuid, path string, startedAt time.Time) (LayerUpload, error) {
|
||||
func (ls *layerStore) newLayerUpload(uuid, path string, startedAt time.Time) (distribution.LayerUpload, error) {
|
||||
fw, err := newFileWriter(ls.repository.driver, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -158,7 +159,9 @@ func (ls *layerStore) path(dgst digest.Digest) (string, error) {
|
|||
if err != nil {
|
||||
switch err := err.(type) {
|
||||
case storagedriver.PathNotFoundError:
|
||||
return "", ErrUnknownLayer{manifest.FSLayer{BlobSum: dgst}}
|
||||
return "", distribution.ErrUnknownLayer{
|
||||
FSLayer: manifest.FSLayer{BlobSum: dgst},
|
||||
}
|
||||
default:
|
||||
return "", err
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution"
|
||||
ctxu "github.com/docker/distribution/context"
|
||||
"github.com/docker/distribution/digest"
|
||||
storagedriver "github.com/docker/distribution/registry/storage/driver"
|
||||
|
@ -24,7 +25,7 @@ type layerUploadController struct {
|
|||
fileWriter
|
||||
}
|
||||
|
||||
var _ LayerUpload = &layerUploadController{}
|
||||
var _ distribution.LayerUpload = &layerUploadController{}
|
||||
|
||||
// Name of the repository under which the layer will be linked.
|
||||
func (luc *layerUploadController) Name() string {
|
||||
|
@ -44,7 +45,7 @@ func (luc *layerUploadController) StartedAt() time.Time {
|
|||
// uploaded layer. The final size and checksum are validated against the
|
||||
// contents of the uploaded layer. The checksum should be provided in the
|
||||
// format <algorithm>:<hex digest>.
|
||||
func (luc *layerUploadController) Finish(digest digest.Digest) (Layer, error) {
|
||||
func (luc *layerUploadController) Finish(digest digest.Digest) (distribution.Layer, error) {
|
||||
ctxu.GetLogger(luc.layerStore.repository.ctx).Debug("(*layerUploadController).Finish")
|
||||
canonical, err := luc.validateLayer(digest)
|
||||
if err != nil {
|
||||
|
@ -93,9 +94,9 @@ func (luc *layerUploadController) validateLayer(dgst digest.Digest) (digest.Dige
|
|||
case tarsum.Version1:
|
||||
default:
|
||||
// version 0 and dev, for now.
|
||||
return "", ErrLayerInvalidDigest{
|
||||
return "", distribution.ErrLayerInvalidDigest{
|
||||
Digest: dgst,
|
||||
Reason: ErrLayerTarSumVersionUnsupported,
|
||||
Reason: distribution.ErrLayerTarSumVersionUnsupported,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,7 +125,7 @@ func (luc *layerUploadController) validateLayer(dgst digest.Digest) (digest.Dige
|
|||
}
|
||||
|
||||
if !digestVerifier.Verified() {
|
||||
return "", ErrLayerInvalidDigest{
|
||||
return "", distribution.ErrLayerInvalidDigest{
|
||||
Digest: dgst,
|
||||
Reason: fmt.Errorf("content does not match digest"),
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/distribution"
|
||||
ctxu "github.com/docker/distribution/context"
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/manifest"
|
||||
|
@ -71,7 +72,7 @@ type manifestStore struct {
|
|||
tagStore *tagStore
|
||||
}
|
||||
|
||||
var _ ManifestService = &manifestStore{}
|
||||
var _ distribution.ManifestService = &manifestStore{}
|
||||
|
||||
// func (ms *manifestStore) Repository() Repository {
|
||||
// return ms.repository
|
||||
|
@ -177,7 +178,7 @@ func (ms *manifestStore) verifyManifest(tag string, mnfst *manifest.SignedManife
|
|||
}
|
||||
|
||||
if !exists {
|
||||
errs = append(errs, ErrUnknownLayer{FSLayer: fsLayer})
|
||||
errs = append(errs, distribution.ErrUnknownLayer{FSLayer: fsLayer})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,11 +4,10 @@ import (
|
|||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution/manifest"
|
||||
|
||||
"code.google.com/p/go-uuid/uuid"
|
||||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/registry/storage"
|
||||
"github.com/docker/distribution/manifest"
|
||||
)
|
||||
|
||||
type bridge struct {
|
||||
|
@ -53,31 +52,31 @@ func NewRequestRecord(id string, r *http.Request) RequestRecord {
|
|||
}
|
||||
}
|
||||
|
||||
func (b *bridge) ManifestPushed(repo storage.Repository, sm *manifest.SignedManifest) error {
|
||||
func (b *bridge) ManifestPushed(repo distribution.Repository, sm *manifest.SignedManifest) error {
|
||||
return b.createManifestEventAndWrite(EventActionPush, repo, sm)
|
||||
}
|
||||
|
||||
func (b *bridge) ManifestPulled(repo storage.Repository, sm *manifest.SignedManifest) error {
|
||||
func (b *bridge) ManifestPulled(repo distribution.Repository, sm *manifest.SignedManifest) error {
|
||||
return b.createManifestEventAndWrite(EventActionPull, repo, sm)
|
||||
}
|
||||
|
||||
func (b *bridge) ManifestDeleted(repo storage.Repository, sm *manifest.SignedManifest) error {
|
||||
func (b *bridge) ManifestDeleted(repo distribution.Repository, sm *manifest.SignedManifest) error {
|
||||
return b.createManifestEventAndWrite(EventActionDelete, repo, sm)
|
||||
}
|
||||
|
||||
func (b *bridge) LayerPushed(repo storage.Repository, layer storage.Layer) error {
|
||||
func (b *bridge) LayerPushed(repo distribution.Repository, layer distribution.Layer) error {
|
||||
return b.createLayerEventAndWrite(EventActionPush, repo, layer.Digest())
|
||||
}
|
||||
|
||||
func (b *bridge) LayerPulled(repo storage.Repository, layer storage.Layer) error {
|
||||
func (b *bridge) LayerPulled(repo distribution.Repository, layer distribution.Layer) error {
|
||||
return b.createLayerEventAndWrite(EventActionPull, repo, layer.Digest())
|
||||
}
|
||||
|
||||
func (b *bridge) LayerDeleted(repo storage.Repository, layer storage.Layer) error {
|
||||
func (b *bridge) LayerDeleted(repo distribution.Repository, layer distribution.Layer) error {
|
||||
return b.createLayerEventAndWrite(EventActionDelete, repo, layer.Digest())
|
||||
}
|
||||
|
||||
func (b *bridge) createManifestEventAndWrite(action string, repo storage.Repository, sm *manifest.SignedManifest) error {
|
||||
func (b *bridge) createManifestEventAndWrite(action string, repo distribution.Repository, sm *manifest.SignedManifest) error {
|
||||
event, err := b.createManifestEvent(action, repo, sm)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -86,7 +85,7 @@ func (b *bridge) createManifestEventAndWrite(action string, repo storage.Reposit
|
|||
return b.sink.Write(*event)
|
||||
}
|
||||
|
||||
func (b *bridge) createManifestEvent(action string, repo storage.Repository, sm *manifest.SignedManifest) (*Event, error) {
|
||||
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()
|
||||
|
@ -112,7 +111,7 @@ func (b *bridge) createManifestEvent(action string, repo storage.Repository, sm
|
|||
return event, nil
|
||||
}
|
||||
|
||||
func (b *bridge) createLayerEventAndWrite(action string, repo storage.Repository, dgst digest.Digest) error {
|
||||
func (b *bridge) createLayerEventAndWrite(action string, repo distribution.Repository, dgst digest.Digest) error {
|
||||
event, err := b.createLayerEvent(action, repo, dgst)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -121,7 +120,7 @@ func (b *bridge) createLayerEventAndWrite(action string, repo storage.Repository
|
|||
return b.sink.Write(*event)
|
||||
}
|
||||
|
||||
func (b *bridge) createLayerEvent(action string, repo storage.Repository, dgst digest.Digest) (*Event, error) {
|
||||
func (b *bridge) createLayerEvent(action string, repo distribution.Repository, dgst digest.Digest) (*Event, error) {
|
||||
event := b.createEvent(action)
|
||||
event.Target.Type = EventTargetTypeBlob
|
||||
event.Target.Name = repo.Name()
|
||||
|
|
|
@ -2,31 +2,31 @@ package notifications
|
|||
|
||||
import (
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/manifest"
|
||||
"github.com/docker/distribution/registry/storage"
|
||||
)
|
||||
|
||||
// ManifestListener describes a set of methods for listening to events related to manifests.
|
||||
type ManifestListener interface {
|
||||
ManifestPushed(repo storage.Repository, sm *manifest.SignedManifest) error
|
||||
ManifestPulled(repo storage.Repository, sm *manifest.SignedManifest) error
|
||||
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 storage.Repository, sm *manifest.SignedManifest) error
|
||||
ManifestDeleted(repo distribution.Repository, sm *manifest.SignedManifest) error
|
||||
}
|
||||
|
||||
// LayerListener describes a listener that can respond to layer related events.
|
||||
type LayerListener interface {
|
||||
LayerPushed(repo storage.Repository, layer storage.Layer) error
|
||||
LayerPulled(repo storage.Repository, layer storage.Layer) error
|
||||
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 storage.Repository, layer storage.Layer) error
|
||||
LayerDeleted(repo distribution.Repository, layer distribution.Layer) error
|
||||
}
|
||||
|
||||
// Listener combines all repository events into a single interface.
|
||||
|
@ -36,26 +36,26 @@ type Listener interface {
|
|||
}
|
||||
|
||||
type repositoryListener struct {
|
||||
storage.Repository
|
||||
distribution.Repository
|
||||
listener Listener
|
||||
}
|
||||
|
||||
// Listen dispatches events on the repository to the listener.
|
||||
func Listen(repo storage.Repository, listener Listener) storage.Repository {
|
||||
func Listen(repo distribution.Repository, listener Listener) distribution.Repository {
|
||||
return &repositoryListener{
|
||||
Repository: repo,
|
||||
listener: listener,
|
||||
}
|
||||
}
|
||||
|
||||
func (rl *repositoryListener) Manifests() storage.ManifestService {
|
||||
func (rl *repositoryListener) Manifests() distribution.ManifestService {
|
||||
return &manifestServiceListener{
|
||||
ManifestService: rl.Repository.Manifests(),
|
||||
parent: rl,
|
||||
}
|
||||
}
|
||||
|
||||
func (rl *repositoryListener) Layers() storage.LayerService {
|
||||
func (rl *repositoryListener) Layers() distribution.LayerService {
|
||||
return &layerServiceListener{
|
||||
LayerService: rl.Repository.Layers(),
|
||||
parent: rl,
|
||||
|
@ -63,7 +63,7 @@ func (rl *repositoryListener) Layers() storage.LayerService {
|
|||
}
|
||||
|
||||
type manifestServiceListener struct {
|
||||
storage.ManifestService
|
||||
distribution.ManifestService
|
||||
parent *repositoryListener
|
||||
}
|
||||
|
||||
|
@ -91,11 +91,11 @@ func (msl *manifestServiceListener) Put(tag string, sm *manifest.SignedManifest)
|
|||
}
|
||||
|
||||
type layerServiceListener struct {
|
||||
storage.LayerService
|
||||
distribution.LayerService
|
||||
parent *repositoryListener
|
||||
}
|
||||
|
||||
func (lsl *layerServiceListener) Fetch(dgst digest.Digest) (storage.Layer, error) {
|
||||
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 {
|
||||
|
@ -106,17 +106,17 @@ func (lsl *layerServiceListener) Fetch(dgst digest.Digest) (storage.Layer, error
|
|||
return layer, err
|
||||
}
|
||||
|
||||
func (lsl *layerServiceListener) Upload() (storage.LayerUpload, error) {
|
||||
func (lsl *layerServiceListener) Upload() (distribution.LayerUpload, error) {
|
||||
lu, err := lsl.LayerService.Upload()
|
||||
return lsl.decorateUpload(lu), err
|
||||
}
|
||||
|
||||
func (lsl *layerServiceListener) Resume(uuid string) (storage.LayerUpload, error) {
|
||||
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 storage.LayerUpload) storage.LayerUpload {
|
||||
func (lsl *layerServiceListener) decorateUpload(lu distribution.LayerUpload) distribution.LayerUpload {
|
||||
return &layerUploadListener{
|
||||
LayerUpload: lu,
|
||||
parent: lsl,
|
||||
|
@ -124,11 +124,11 @@ func (lsl *layerServiceListener) decorateUpload(lu storage.LayerUpload) storage.
|
|||
}
|
||||
|
||||
type layerUploadListener struct {
|
||||
storage.LayerUpload
|
||||
distribution.LayerUpload
|
||||
parent *layerServiceListener
|
||||
}
|
||||
|
||||
func (lul *layerUploadListener) Finish(dgst digest.Digest) (storage.Layer, error) {
|
||||
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 {
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/manifest"
|
||||
"github.com/docker/distribution/registry/storage"
|
||||
|
@ -44,40 +45,40 @@ type testListener struct {
|
|||
ops map[string]int
|
||||
}
|
||||
|
||||
func (tl *testListener) ManifestPushed(repo storage.Repository, sm *manifest.SignedManifest) error {
|
||||
func (tl *testListener) ManifestPushed(repo distribution.Repository, sm *manifest.SignedManifest) error {
|
||||
tl.ops["manifest:push"]++
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tl *testListener) ManifestPulled(repo storage.Repository, sm *manifest.SignedManifest) error {
|
||||
func (tl *testListener) ManifestPulled(repo distribution.Repository, sm *manifest.SignedManifest) error {
|
||||
tl.ops["manifest:pull"]++
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tl *testListener) ManifestDeleted(repo storage.Repository, sm *manifest.SignedManifest) error {
|
||||
func (tl *testListener) ManifestDeleted(repo distribution.Repository, sm *manifest.SignedManifest) error {
|
||||
tl.ops["manifest:delete"]++
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tl *testListener) LayerPushed(repo storage.Repository, layer storage.Layer) error {
|
||||
func (tl *testListener) LayerPushed(repo distribution.Repository, layer distribution.Layer) error {
|
||||
tl.ops["layer:push"]++
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tl *testListener) LayerPulled(repo storage.Repository, layer storage.Layer) error {
|
||||
func (tl *testListener) LayerPulled(repo distribution.Repository, layer distribution.Layer) error {
|
||||
tl.ops["layer:pull"]++
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tl *testListener) LayerDeleted(repo storage.Repository, layer storage.Layer) error {
|
||||
func (tl *testListener) LayerDeleted(repo distribution.Repository, layer distribution.Layer) error {
|
||||
tl.ops["layer:delete"]++
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkExerciseRegistry takes the registry through all of its operations,
|
||||
// carrying out generic checks.
|
||||
func checkExerciseRepository(t *testing.T, repository storage.Repository) {
|
||||
func checkExerciseRepository(t *testing.T, repository distribution.Repository) {
|
||||
// TODO(stevvooe): This would be a nice testutil function. Basically, it
|
||||
// takes the registry through a common set of operations. This could be
|
||||
// used to make cross-cutting updates by changing internals that affect
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"github.com/docker/distribution"
|
||||
storagedriver "github.com/docker/distribution/registry/storage/driver"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
@ -16,7 +17,7 @@ type registry struct {
|
|||
// NewRegistryWithDriver creates a new registry instance from the provided
|
||||
// driver. The resulting registry may be shared by multiple goroutines but is
|
||||
// cheap to allocate.
|
||||
func NewRegistryWithDriver(driver storagedriver.StorageDriver) Registry {
|
||||
func NewRegistryWithDriver(driver storagedriver.StorageDriver) distribution.Registry {
|
||||
bs := &blobStore{}
|
||||
|
||||
reg := ®istry{
|
||||
|
@ -35,7 +36,7 @@ func NewRegistryWithDriver(driver storagedriver.StorageDriver) Registry {
|
|||
// Repository returns an instance of the repository tied to the registry.
|
||||
// Instances should not be shared between goroutines but are cheap to
|
||||
// allocate. In general, they should be request scoped.
|
||||
func (reg *registry) Repository(ctx context.Context, name string) Repository {
|
||||
func (reg *registry) Repository(ctx context.Context, name string) distribution.Repository {
|
||||
return &repository{
|
||||
ctx: ctx,
|
||||
registry: reg,
|
||||
|
@ -58,7 +59,7 @@ func (repo *repository) Name() string {
|
|||
// Manifests returns an instance of ManifestService. Instantiation is cheap and
|
||||
// may be context sensitive in the future. The instance should be used similar
|
||||
// to a request local.
|
||||
func (repo *repository) Manifests() ManifestService {
|
||||
func (repo *repository) Manifests() distribution.ManifestService {
|
||||
return &manifestStore{
|
||||
repository: repo,
|
||||
revisionStore: &revisionStore{
|
||||
|
@ -73,7 +74,7 @@ func (repo *repository) Manifests() ManifestService {
|
|||
// Layers returns an instance of the LayerService. Instantiation is cheap and
|
||||
// may be context sensitive in the future. The instance should be used similar
|
||||
// to a request local.
|
||||
func (repo *repository) Layers() LayerService {
|
||||
func (repo *repository) Layers() distribution.LayerService {
|
||||
return &layerStore{
|
||||
repository: repo,
|
||||
}
|
||||
|
|
|
@ -1,84 +0,0 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/manifest"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// TODO(stevvooe): These types need to be moved out of the storage package.
|
||||
|
||||
// Registry represents a collection of repositories, addressable by name.
|
||||
type Registry interface {
|
||||
// Repository should return a reference to the named repository. The
|
||||
// registry may or may not have the repository but should always return a
|
||||
// reference.
|
||||
Repository(ctx context.Context, name string) Repository
|
||||
}
|
||||
|
||||
// Repository is a named collection of manifests and layers.
|
||||
type Repository interface {
|
||||
// Name returns the name of the repository.
|
||||
Name() string
|
||||
|
||||
// Manifests returns a reference to this repository's manifest service.
|
||||
Manifests() ManifestService
|
||||
|
||||
// Layers returns a reference to this repository's layers service.
|
||||
Layers() LayerService
|
||||
}
|
||||
|
||||
// ManifestService provides operations on image manifests.
|
||||
type ManifestService interface {
|
||||
// Tags lists the tags under the named repository.
|
||||
Tags() ([]string, error)
|
||||
|
||||
// Exists returns true if the manifest exists.
|
||||
Exists(tag string) (bool, error)
|
||||
|
||||
// Get retrieves the named manifest, if it exists.
|
||||
Get(tag string) (*manifest.SignedManifest, error)
|
||||
|
||||
// Put creates or updates the named manifest.
|
||||
// Put(tag string, manifest *manifest.SignedManifest) (digest.Digest, error)
|
||||
Put(tag string, manifest *manifest.SignedManifest) error
|
||||
|
||||
// Delete removes the named manifest, if it exists.
|
||||
Delete(tag string) error
|
||||
|
||||
// TODO(stevvooe): There are several changes that need to be done to this
|
||||
// interface:
|
||||
//
|
||||
// 1. Get(tag string) should be GetByTag(tag string)
|
||||
// 2. Put(tag string, manifest *manifest.SignedManifest) should be
|
||||
// Put(manifest *manifest.SignedManifest). The method can read the
|
||||
// tag on manifest to automatically tag it in the repository.
|
||||
// 3. Need a GetByDigest(dgst digest.Digest) method.
|
||||
// 4. Allow explicit tagging with Tag(digest digest.Digest, tag string)
|
||||
// 5. Support reading tags with a re-entrant reader to avoid large
|
||||
// allocations in the registry.
|
||||
// 6. Long-term: Provide All() method that lets one scroll through all of
|
||||
// the manifest entries.
|
||||
// 7. Long-term: break out concept of signing from manifests. This is
|
||||
// really a part of the distribution sprint.
|
||||
// 8. Long-term: Manifest should be an interface. This code shouldn't
|
||||
// really be concerned with the storage format.
|
||||
}
|
||||
|
||||
// LayerService provides operations on layer files in a backend storage.
|
||||
type LayerService interface {
|
||||
// Exists returns true if the layer exists.
|
||||
Exists(digest digest.Digest) (bool, error)
|
||||
|
||||
// Fetch the layer identifed by TarSum.
|
||||
Fetch(digest digest.Digest) (Layer, error)
|
||||
|
||||
// Upload begins a layer upload to repository identified by name,
|
||||
// returning a handle.
|
||||
Upload() (LayerUpload, error)
|
||||
|
||||
// Resume continues an in progress layer upload, returning a handle to the
|
||||
// upload. The caller should seek to the latest desired upload location
|
||||
// before proceeding.
|
||||
Resume(uuid string) (LayerUpload, error)
|
||||
}
|
Loading…
Reference in a new issue