Export storage.CreateOptions in top-level package
Let the options for `BlobStore.Create()` be modified in middleware wrappers. Signed-off-by: Michal Minar <miminar@redhat.com>master
							parent
							
								
									1fc752c718
								
							
						
					
					
						commit
						3f1434525b
					
				
							
								
								
									
										9
									
								
								blobs.go
								
								
								
								
							
							
						
						
									
										9
									
								
								blobs.go
								
								
								
								
							| 
						 | 
					@ -192,6 +192,15 @@ type BlobCreateOption interface {
 | 
				
			||||||
	Apply(interface{}) error
 | 
						Apply(interface{}) error
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CreateOptions is a collection of blob creation modifiers relevant to general
 | 
				
			||||||
 | 
					// blob storage intended to be configured by the BlobCreateOption.Apply method.
 | 
				
			||||||
 | 
					type CreateOptions struct {
 | 
				
			||||||
 | 
						Mount struct {
 | 
				
			||||||
 | 
							ShouldMount bool
 | 
				
			||||||
 | 
							From        reference.Canonical
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// BlobWriter provides a handle for inserting data into a blob store.
 | 
					// BlobWriter provides a handle for inserting data into a blob store.
 | 
				
			||||||
// Instances should be obtained from BlobWriteService.Writer and
 | 
					// Instances should be obtained from BlobWriteService.Writer and
 | 
				
			||||||
// BlobWriteService.Resume. If supported by the store, a writer can be
 | 
					// BlobWriteService.Resume. If supported by the store, a writer can be
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -672,15 +672,6 @@ func (bs *blobs) Put(ctx context.Context, mediaType string, p []byte) (distribut
 | 
				
			||||||
	return writer.Commit(ctx, desc)
 | 
						return writer.Commit(ctx, desc)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// createOptions is a collection of blob creation modifiers relevant to general
 | 
					 | 
				
			||||||
// blob storage intended to be configured by the BlobCreateOption.Apply method.
 | 
					 | 
				
			||||||
type createOptions struct {
 | 
					 | 
				
			||||||
	Mount struct {
 | 
					 | 
				
			||||||
		ShouldMount bool
 | 
					 | 
				
			||||||
		From        reference.Canonical
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type optionFunc func(interface{}) error
 | 
					type optionFunc func(interface{}) error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (f optionFunc) Apply(v interface{}) error {
 | 
					func (f optionFunc) Apply(v interface{}) error {
 | 
				
			||||||
| 
						 | 
					@ -691,7 +682,7 @@ func (f optionFunc) Apply(v interface{}) error {
 | 
				
			||||||
// mounted from the given canonical reference.
 | 
					// mounted from the given canonical reference.
 | 
				
			||||||
func WithMountFrom(ref reference.Canonical) distribution.BlobCreateOption {
 | 
					func WithMountFrom(ref reference.Canonical) distribution.BlobCreateOption {
 | 
				
			||||||
	return optionFunc(func(v interface{}) error {
 | 
						return optionFunc(func(v interface{}) error {
 | 
				
			||||||
		opts, ok := v.(*createOptions)
 | 
							opts, ok := v.(*distribution.CreateOptions)
 | 
				
			||||||
		if !ok {
 | 
							if !ok {
 | 
				
			||||||
			return fmt.Errorf("unexpected options type: %T", v)
 | 
								return fmt.Errorf("unexpected options type: %T", v)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -704,7 +695,7 @@ func WithMountFrom(ref reference.Canonical) distribution.BlobCreateOption {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (bs *blobs) Create(ctx context.Context, options ...distribution.BlobCreateOption) (distribution.BlobWriter, error) {
 | 
					func (bs *blobs) Create(ctx context.Context, options ...distribution.BlobCreateOption) (distribution.BlobWriter, error) {
 | 
				
			||||||
	var opts createOptions
 | 
						var opts distribution.CreateOptions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, option := range options {
 | 
						for _, option := range options {
 | 
				
			||||||
		err := option.Apply(&opts)
 | 
							err := option.Apply(&opts)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -101,15 +101,6 @@ func (lbs *linkedBlobStore) Put(ctx context.Context, mediaType string, p []byte)
 | 
				
			||||||
	return desc, lbs.linkBlob(ctx, desc)
 | 
						return desc, lbs.linkBlob(ctx, desc)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// createOptions is a collection of blob creation modifiers relevant to general
 | 
					 | 
				
			||||||
// blob storage intended to be configured by the BlobCreateOption.Apply method.
 | 
					 | 
				
			||||||
type createOptions struct {
 | 
					 | 
				
			||||||
	Mount struct {
 | 
					 | 
				
			||||||
		ShouldMount bool
 | 
					 | 
				
			||||||
		From        reference.Canonical
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type optionFunc func(interface{}) error
 | 
					type optionFunc func(interface{}) error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (f optionFunc) Apply(v interface{}) error {
 | 
					func (f optionFunc) Apply(v interface{}) error {
 | 
				
			||||||
| 
						 | 
					@ -120,7 +111,7 @@ func (f optionFunc) Apply(v interface{}) error {
 | 
				
			||||||
// mounted from the given canonical reference.
 | 
					// mounted from the given canonical reference.
 | 
				
			||||||
func WithMountFrom(ref reference.Canonical) distribution.BlobCreateOption {
 | 
					func WithMountFrom(ref reference.Canonical) distribution.BlobCreateOption {
 | 
				
			||||||
	return optionFunc(func(v interface{}) error {
 | 
						return optionFunc(func(v interface{}) error {
 | 
				
			||||||
		opts, ok := v.(*createOptions)
 | 
							opts, ok := v.(*distribution.CreateOptions)
 | 
				
			||||||
		if !ok {
 | 
							if !ok {
 | 
				
			||||||
			return fmt.Errorf("unexpected options type: %T", v)
 | 
								return fmt.Errorf("unexpected options type: %T", v)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -136,7 +127,7 @@ func WithMountFrom(ref reference.Canonical) distribution.BlobCreateOption {
 | 
				
			||||||
func (lbs *linkedBlobStore) Create(ctx context.Context, options ...distribution.BlobCreateOption) (distribution.BlobWriter, error) {
 | 
					func (lbs *linkedBlobStore) Create(ctx context.Context, options ...distribution.BlobCreateOption) (distribution.BlobWriter, error) {
 | 
				
			||||||
	context.GetLogger(ctx).Debug("(*linkedBlobStore).Writer")
 | 
						context.GetLogger(ctx).Debug("(*linkedBlobStore).Writer")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var opts createOptions
 | 
						var opts distribution.CreateOptions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, option := range options {
 | 
						for _, option := range options {
 | 
				
			||||||
		err := option.Apply(&opts)
 | 
							err := option.Apply(&opts)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,78 @@
 | 
				
			||||||
 | 
					package storage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/docker/distribution"
 | 
				
			||||||
 | 
						"github.com/docker/distribution/context"
 | 
				
			||||||
 | 
						"github.com/docker/distribution/digest"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/docker/distribution/reference"
 | 
				
			||||||
 | 
						"github.com/docker/distribution/testutil"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestLinkedBlobStoreCreateWithMountFrom(t *testing.T) {
 | 
				
			||||||
 | 
						fooRepoName, _ := reference.ParseNamed("nm/foo")
 | 
				
			||||||
 | 
						fooEnv := newManifestStoreTestEnv(t, fooRepoName, "thetag")
 | 
				
			||||||
 | 
						ctx := context.Background()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Build up some test layers and add them to the manifest, saving the
 | 
				
			||||||
 | 
						// readseekers for upload later.
 | 
				
			||||||
 | 
						testLayers := map[digest.Digest]io.ReadSeeker{}
 | 
				
			||||||
 | 
						for i := 0; i < 2; i++ {
 | 
				
			||||||
 | 
							rs, ds, err := testutil.CreateRandomTarFile()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								t.Fatalf("unexpected error generating test layer file")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							dgst := digest.Digest(ds)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							testLayers[digest.Digest(dgst)] = rs
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// upload the layers to foo/bar
 | 
				
			||||||
 | 
						for dgst, rs := range testLayers {
 | 
				
			||||||
 | 
							wr, err := fooEnv.repository.Blobs(fooEnv.ctx).Create(fooEnv.ctx)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								t.Fatalf("unexpected error creating test upload: %v", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if _, err := io.Copy(wr, rs); err != nil {
 | 
				
			||||||
 | 
								t.Fatalf("unexpected error copying to upload: %v", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if _, err := wr.Commit(fooEnv.ctx, distribution.Descriptor{Digest: dgst}); err != nil {
 | 
				
			||||||
 | 
								t.Fatalf("unexpected error finishing upload: %v", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// create another repository nm/bar
 | 
				
			||||||
 | 
						barRepoName, _ := reference.ParseNamed("nm/bar")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						barRepo, err := fooEnv.registry.Repository(ctx, barRepoName)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("unexpected error getting repo: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// cross-repo mount the test layers into a nm/bar
 | 
				
			||||||
 | 
						for dgst := range testLayers {
 | 
				
			||||||
 | 
							fooCanonical, _ := reference.WithDigest(fooRepoName, dgst)
 | 
				
			||||||
 | 
							option := WithMountFrom(fooCanonical)
 | 
				
			||||||
 | 
							// ensure we can instrospect it
 | 
				
			||||||
 | 
							createOpts := distribution.CreateOptions{}
 | 
				
			||||||
 | 
							if err := option.Apply(&createOpts); err != nil {
 | 
				
			||||||
 | 
								t.Fatalf("failed to apply MountFrom option: %v", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if !createOpts.Mount.ShouldMount || createOpts.Mount.From.String() != fooCanonical.String() {
 | 
				
			||||||
 | 
								t.Fatalf("unexpected create options: %#+v", createOpts.Mount)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							_, err := barRepo.Blobs(ctx).Create(ctx, WithMountFrom(fooCanonical))
 | 
				
			||||||
 | 
							if err == nil {
 | 
				
			||||||
 | 
								t.Fatalf("unexpected non-error while mounting from %q: %v", fooRepoName.String(), err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if _, ok := err.(distribution.ErrBlobMounted); !ok {
 | 
				
			||||||
 | 
								t.Fatalf("expected ErrMountFrom error, not %T: %v", err, err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue