forked from TrueCloudLab/distribution
Manifest and layer soft deletion.
Implement the delete API by implementing soft delete for layers and blobs by removing link files and updating the blob descriptor cache. Deletion is configurable - if it is disabled API calls will return an unsupported error. We invalidate the blob descriptor cache by changing the linkedBlobStore's blobStatter to a blobDescriptorService and naming it blobAccessController. Delete() is added throughout the relevant API to support this functionality. Signed-off-by: Richard Scothern <richard.scothern@gmail.com>
This commit is contained in:
parent
7dbe35176d
commit
390bb97a88
21 changed files with 816 additions and 92 deletions
|
@ -16,10 +16,11 @@ import (
|
|||
// that grant access to the global blob store.
|
||||
type linkedBlobStore struct {
|
||||
*blobStore
|
||||
blobServer distribution.BlobServer
|
||||
statter distribution.BlobStatter
|
||||
repository distribution.Repository
|
||||
ctx context.Context // only to be used where context can't come through method args
|
||||
blobServer distribution.BlobServer
|
||||
blobAccessController distribution.BlobDescriptorService
|
||||
repository distribution.Repository
|
||||
ctx context.Context // only to be used where context can't come through method args
|
||||
deleteEnabled bool
|
||||
|
||||
// linkPath allows one to control the repository blob link set to which
|
||||
// the blob store dispatches. This is required because manifest and layer
|
||||
|
@ -31,7 +32,7 @@ type linkedBlobStore struct {
|
|||
var _ distribution.BlobStore = &linkedBlobStore{}
|
||||
|
||||
func (lbs *linkedBlobStore) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) {
|
||||
return lbs.statter.Stat(ctx, dgst)
|
||||
return lbs.blobAccessController.Stat(ctx, dgst)
|
||||
}
|
||||
|
||||
func (lbs *linkedBlobStore) Get(ctx context.Context, dgst digest.Digest) ([]byte, error) {
|
||||
|
@ -67,6 +68,10 @@ func (lbs *linkedBlobStore) ServeBlob(ctx context.Context, w http.ResponseWriter
|
|||
}
|
||||
|
||||
func (lbs *linkedBlobStore) Put(ctx context.Context, mediaType string, p []byte) (distribution.Descriptor, error) {
|
||||
dgst, err := digest.FromBytes(p)
|
||||
if err != nil {
|
||||
return distribution.Descriptor{}, err
|
||||
}
|
||||
// Place the data in the blob store first.
|
||||
desc, err := lbs.blobStore.Put(ctx, mediaType, p)
|
||||
if err != nil {
|
||||
|
@ -74,6 +79,10 @@ func (lbs *linkedBlobStore) Put(ctx context.Context, mediaType string, p []byte)
|
|||
return distribution.Descriptor{}, err
|
||||
}
|
||||
|
||||
if err := lbs.blobAccessController.SetDescriptor(ctx, dgst, desc); err != nil {
|
||||
return distribution.Descriptor{}, err
|
||||
}
|
||||
|
||||
// TODO(stevvooe): Write out mediatype if incoming differs from what is
|
||||
// returned by Put above. Note that we should allow updates for a given
|
||||
// repository.
|
||||
|
@ -153,7 +162,26 @@ func (lbs *linkedBlobStore) Resume(ctx context.Context, id string) (distribution
|
|||
return lbs.newBlobUpload(ctx, id, path, startedAt)
|
||||
}
|
||||
|
||||
// newLayerUpload allocates a new upload controller with the given state.
|
||||
func (lbs *linkedBlobStore) Delete(ctx context.Context, dgst digest.Digest) error {
|
||||
if !lbs.deleteEnabled {
|
||||
return distribution.ErrUnsupported
|
||||
}
|
||||
|
||||
// Ensure the blob is available for deletion
|
||||
_, err := lbs.blobAccessController.Stat(ctx, dgst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = lbs.blobAccessController.Clear(ctx, dgst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// newBlobUpload allocates a new upload controller with the given state.
|
||||
func (lbs *linkedBlobStore) newBlobUpload(ctx context.Context, uuid, path string, startedAt time.Time) (distribution.BlobWriter, error) {
|
||||
fw, err := newFileWriter(ctx, lbs.driver, path)
|
||||
if err != nil {
|
||||
|
@ -213,7 +241,7 @@ type linkedBlobStatter struct {
|
|||
linkPath func(pm *pathMapper, name string, dgst digest.Digest) (string, error)
|
||||
}
|
||||
|
||||
var _ distribution.BlobStatter = &linkedBlobStatter{}
|
||||
var _ distribution.BlobDescriptorService = &linkedBlobStatter{}
|
||||
|
||||
func (lbs *linkedBlobStatter) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) {
|
||||
blobLinkPath, err := lbs.linkPath(lbs.pm, lbs.repository.Name(), dgst)
|
||||
|
@ -246,6 +274,20 @@ func (lbs *linkedBlobStatter) Stat(ctx context.Context, dgst digest.Digest) (dis
|
|||
return lbs.blobStore.statter.Stat(ctx, target)
|
||||
}
|
||||
|
||||
func (lbs *linkedBlobStatter) Clear(ctx context.Context, dgst digest.Digest) error {
|
||||
blobLinkPath, err := lbs.linkPath(lbs.pm, lbs.repository.Name(), dgst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return lbs.blobStore.driver.Delete(ctx, blobLinkPath)
|
||||
}
|
||||
|
||||
func (lbs *linkedBlobStatter) SetDescriptor(ctx context.Context, dgst digest.Digest, desc distribution.Descriptor) error {
|
||||
// The canonical descriptor for a blob is set at the commit phase of upload
|
||||
return nil
|
||||
}
|
||||
|
||||
// blobLinkPath provides the path to the blob link, also known as layers.
|
||||
func blobLinkPath(pm *pathMapper, name string, dgst digest.Digest) (string, error) {
|
||||
return pm.path(layerLinkPathSpec{name: name, digest: dgst})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue