Allow Manifest Service to be configured with function arguments
Signed-off-by: Richard Scothern <richard.scothern@gmail.com>master
							parent
							
								
									b318e01f7d
								
							
						
					
					
						commit
						cd31d466e4
					
				| 
						 | 
					@ -70,18 +70,20 @@ func (r *repository) Blobs(ctx context.Context) distribution.BlobStore {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *repository) Manifests() distribution.ManifestService {
 | 
					func (r *repository) Manifests(ctx context.Context, options ...distribution.ManifestServiceOption) (distribution.ManifestService, error) {
 | 
				
			||||||
 | 
						// todo(richardscothern): options should be sent over the wire
 | 
				
			||||||
	return &manifests{
 | 
						return &manifests{
 | 
				
			||||||
		name:   r.Name(),
 | 
							name:   r.Name(),
 | 
				
			||||||
		ub:     r.ub,
 | 
							ub:     r.ub,
 | 
				
			||||||
		client: r.client,
 | 
							client: r.client,
 | 
				
			||||||
		etags:  make(map[string]string),
 | 
							etags:  make(map[string]string),
 | 
				
			||||||
	}
 | 
						}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *repository) Signatures() distribution.SignatureService {
 | 
					func (r *repository) Signatures() distribution.SignatureService {
 | 
				
			||||||
 | 
						ms, _ := r.Manifests(r.context)
 | 
				
			||||||
	return &signatures{
 | 
						return &signatures{
 | 
				
			||||||
		manifests: r.Manifests(),
 | 
							manifests: ms,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -236,6 +238,8 @@ func (ms *manifests) Put(m *manifest.SignedManifest) error {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// todo(richardscothern): do something with options here when they become applicable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	putRequest, err := http.NewRequest("PUT", manifestURL, bytes.NewReader(m.Raw))
 | 
						putRequest, err := http.NewRequest("PUT", manifestURL, bytes.NewReader(m.Raw))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -492,6 +492,7 @@ func checkEqualManifest(m1, m2 *manifest.SignedManifest) error {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestManifestFetch(t *testing.T) {
 | 
					func TestManifestFetch(t *testing.T) {
 | 
				
			||||||
 | 
						ctx := context.Background()
 | 
				
			||||||
	repo := "test.example.com/repo"
 | 
						repo := "test.example.com/repo"
 | 
				
			||||||
	m1, dgst := newRandomSchemaV1Manifest(repo, "latest", 6)
 | 
						m1, dgst := newRandomSchemaV1Manifest(repo, "latest", 6)
 | 
				
			||||||
	var m testutil.RequestResponseMap
 | 
						var m testutil.RequestResponseMap
 | 
				
			||||||
| 
						 | 
					@ -504,7 +505,10 @@ func TestManifestFetch(t *testing.T) {
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ms := r.Manifests()
 | 
						ms, err := r.Manifests(ctx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ok, err := ms.Exists(dgst)
 | 
						ok, err := ms.Exists(dgst)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
| 
						 | 
					@ -536,8 +540,12 @@ func TestManifestFetchWithEtag(t *testing.T) {
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						ctx := context.Background()
 | 
				
			||||||
 | 
						ms, err := r.Manifests(ctx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ms := r.Manifests()
 | 
					 | 
				
			||||||
	m2, err := ms.GetByTag("latest", AddEtagToTag("latest", d1.String()))
 | 
						m2, err := ms.GetByTag("latest", AddEtagToTag("latest", d1.String()))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
| 
						 | 
					@ -572,8 +580,12 @@ func TestManifestDelete(t *testing.T) {
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						ctx := context.Background()
 | 
				
			||||||
 | 
						ms, err := r.Manifests(ctx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ms := r.Manifests()
 | 
					 | 
				
			||||||
	if err := ms.Delete(dgst1); err != nil {
 | 
						if err := ms.Delete(dgst1); err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -609,8 +621,12 @@ func TestManifestPut(t *testing.T) {
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						ctx := context.Background()
 | 
				
			||||||
 | 
						ms, err := r.Manifests(ctx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ms := r.Manifests()
 | 
					 | 
				
			||||||
	if err := ms.Put(m1); err != nil {
 | 
						if err := ms.Put(m1); err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -653,8 +669,12 @@ func TestManifestTags(t *testing.T) {
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						ctx := context.Background()
 | 
				
			||||||
 | 
						ms, err := r.Manifests(ctx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ms := r.Manifests()
 | 
					 | 
				
			||||||
	tags, err := ms.Tags()
 | 
						tags, err := ms.Tags()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
| 
						 | 
					@ -691,7 +711,11 @@ func TestManifestUnauthorized(t *testing.T) {
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ms := r.Manifests()
 | 
						ctx := context.Background()
 | 
				
			||||||
 | 
						ms, err := r.Manifests(ctx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_, err = ms.Get(dgst)
 | 
						_, err = ms.Get(dgst)
 | 
				
			||||||
	if err == nil {
 | 
						if err == nil {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -50,13 +50,13 @@ type imageManifestHandler struct {
 | 
				
			||||||
// GetImageManifest fetches the image manifest from the storage backend, if it exists.
 | 
					// GetImageManifest fetches the image manifest from the storage backend, if it exists.
 | 
				
			||||||
func (imh *imageManifestHandler) GetImageManifest(w http.ResponseWriter, r *http.Request) {
 | 
					func (imh *imageManifestHandler) GetImageManifest(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
	ctxu.GetLogger(imh).Debug("GetImageManifest")
 | 
						ctxu.GetLogger(imh).Debug("GetImageManifest")
 | 
				
			||||||
	manifests := imh.Repository.Manifests()
 | 
						manifests, err := imh.Repository.Manifests(imh)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
	var (
 | 
							imh.Errors = append(imh.Errors, err)
 | 
				
			||||||
		sm  *manifest.SignedManifest
 | 
							return
 | 
				
			||||||
		err error
 | 
						}
 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var sm *manifest.SignedManifest
 | 
				
			||||||
	if imh.Tag != "" {
 | 
						if imh.Tag != "" {
 | 
				
			||||||
		sm, err = manifests.GetByTag(imh.Tag)
 | 
							sm, err = manifests.GetByTag(imh.Tag)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
| 
						 | 
					@ -106,7 +106,12 @@ func etagMatch(r *http.Request, etag string) bool {
 | 
				
			||||||
// PutImageManifest validates and stores and image in the registry.
 | 
					// PutImageManifest validates and stores and image in the registry.
 | 
				
			||||||
func (imh *imageManifestHandler) PutImageManifest(w http.ResponseWriter, r *http.Request) {
 | 
					func (imh *imageManifestHandler) PutImageManifest(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
	ctxu.GetLogger(imh).Debug("PutImageManifest")
 | 
						ctxu.GetLogger(imh).Debug("PutImageManifest")
 | 
				
			||||||
	manifests := imh.Repository.Manifests()
 | 
						manifests, err := imh.Repository.Manifests(imh)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							imh.Errors = append(imh.Errors, err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dec := json.NewDecoder(r.Body)
 | 
						dec := json.NewDecoder(r.Body)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var manifest manifest.SignedManifest
 | 
						var manifest manifest.SignedManifest
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,7 +34,11 @@ type tagsAPIResponse struct {
 | 
				
			||||||
// GetTags returns a json list of tags for a specific image name.
 | 
					// GetTags returns a json list of tags for a specific image name.
 | 
				
			||||||
func (th *tagsHandler) GetTags(w http.ResponseWriter, r *http.Request) {
 | 
					func (th *tagsHandler) GetTags(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
	defer r.Body.Close()
 | 
						defer r.Body.Close()
 | 
				
			||||||
	manifests := th.Repository.Manifests()
 | 
						manifests, err := th.Repository.Manifests(th)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							th.Errors = append(th.Errors, err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tags, err := manifests.Tags()
 | 
						tags, err := manifests.Tags()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,10 +11,11 @@ import (
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type manifestStore struct {
 | 
					type manifestStore struct {
 | 
				
			||||||
	repository    *repository
 | 
						repository                 *repository
 | 
				
			||||||
	revisionStore *revisionStore
 | 
						revisionStore              *revisionStore
 | 
				
			||||||
	tagStore      *tagStore
 | 
						tagStore                   *tagStore
 | 
				
			||||||
	ctx           context.Context
 | 
						ctx                        context.Context
 | 
				
			||||||
 | 
						skipDependencyVerification bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var _ distribution.ManifestService = &manifestStore{}
 | 
					var _ distribution.ManifestService = &manifestStore{}
 | 
				
			||||||
| 
						 | 
					@ -39,10 +40,19 @@ func (ms *manifestStore) Get(dgst digest.Digest) (*manifest.SignedManifest, erro
 | 
				
			||||||
	return ms.revisionStore.get(ms.ctx, dgst)
 | 
						return ms.revisionStore.get(ms.ctx, dgst)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SkipLayerVerification allows a manifest to be Put before it's
 | 
				
			||||||
 | 
					// layers are on the filesystem
 | 
				
			||||||
 | 
					func SkipLayerVerification(ms distribution.ManifestService) error {
 | 
				
			||||||
 | 
						if ms, ok := ms.(*manifestStore); ok {
 | 
				
			||||||
 | 
							ms.skipDependencyVerification = true
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return fmt.Errorf("skip layer verification only valid for manifeststore")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ms *manifestStore) Put(manifest *manifest.SignedManifest) error {
 | 
					func (ms *manifestStore) Put(manifest *manifest.SignedManifest) error {
 | 
				
			||||||
	context.GetLogger(ms.ctx).Debug("(*manifestStore).Put")
 | 
						context.GetLogger(ms.ctx).Debug("(*manifestStore).Put")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Verify the manifest.
 | 
					 | 
				
			||||||
	if err := ms.verifyManifest(ms.ctx, manifest); err != nil {
 | 
						if err := ms.verifyManifest(ms.ctx, manifest); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -113,18 +123,19 @@ func (ms *manifestStore) verifyManifest(ctx context.Context, mnfst *manifest.Sig
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, fsLayer := range mnfst.FSLayers {
 | 
						if !ms.skipDependencyVerification {
 | 
				
			||||||
		_, err := ms.repository.Blobs(ctx).Stat(ctx, fsLayer.BlobSum)
 | 
							for _, fsLayer := range mnfst.FSLayers {
 | 
				
			||||||
		if err != nil {
 | 
								_, err := ms.repository.Blobs(ctx).Stat(ctx, fsLayer.BlobSum)
 | 
				
			||||||
			if err != distribution.ErrBlobUnknown {
 | 
								if err != nil {
 | 
				
			||||||
				errs = append(errs, err)
 | 
									if err != distribution.ErrBlobUnknown {
 | 
				
			||||||
			}
 | 
										errs = append(errs, err)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// On error here, we always append unknown blob errors.
 | 
									// On error here, we always append unknown blob errors.
 | 
				
			||||||
			errs = append(errs, distribution.ErrManifestBlobUnknown{Digest: fsLayer.BlobSum})
 | 
									errs = append(errs, distribution.ErrManifestBlobUnknown{Digest: fsLayer.BlobSum})
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if len(errs) != 0 {
 | 
						if len(errs) != 0 {
 | 
				
			||||||
		return errs
 | 
							return errs
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -48,7 +48,11 @@ func newManifestStoreTestEnv(t *testing.T, name, tag string) *manifestStoreTestE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestManifestStorage(t *testing.T) {
 | 
					func TestManifestStorage(t *testing.T) {
 | 
				
			||||||
	env := newManifestStoreTestEnv(t, "foo/bar", "thetag")
 | 
						env := newManifestStoreTestEnv(t, "foo/bar", "thetag")
 | 
				
			||||||
	ms := env.repository.Manifests()
 | 
						ctx := context.Background()
 | 
				
			||||||
 | 
						ms, err := env.repository.Manifests(ctx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	exists, err := ms.ExistsByTag(env.tag)
 | 
						exists, err := ms.ExistsByTag(env.tag)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
| 
						 | 
					@ -97,14 +101,14 @@ func TestManifestStorage(t *testing.T) {
 | 
				
			||||||
		t.Fatalf("unexpected error generating private key: %v", err)
 | 
							t.Fatalf("unexpected error generating private key: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sm, err := manifest.Sign(&m, pk)
 | 
						sm, merr := manifest.Sign(&m, pk)
 | 
				
			||||||
	if err != nil {
 | 
						if merr != nil {
 | 
				
			||||||
		t.Fatalf("error signing manifest: %v", err)
 | 
							t.Fatalf("error signing manifest: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = ms.Put(sm)
 | 
						err = ms.Put(sm)
 | 
				
			||||||
	if err == nil {
 | 
						if err == nil {
 | 
				
			||||||
		t.Fatalf("expected errors putting manifest")
 | 
							t.Fatalf("expected errors putting manifest with full verification")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch err := err.(type) {
 | 
						switch err := err.(type) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -99,15 +99,15 @@ func (repo *repository) Name() string {
 | 
				
			||||||
// Manifests returns an instance of ManifestService. Instantiation is cheap and
 | 
					// Manifests returns an instance of ManifestService. Instantiation is cheap and
 | 
				
			||||||
// may be context sensitive in the future. The instance should be used similar
 | 
					// may be context sensitive in the future. The instance should be used similar
 | 
				
			||||||
// to a request local.
 | 
					// to a request local.
 | 
				
			||||||
func (repo *repository) Manifests() distribution.ManifestService {
 | 
					func (repo *repository) Manifests(ctx context.Context, options ...distribution.ManifestServiceOption) (distribution.ManifestService, error) {
 | 
				
			||||||
	return &manifestStore{
 | 
						ms := &manifestStore{
 | 
				
			||||||
		ctx:        repo.ctx,
 | 
							ctx:        ctx,
 | 
				
			||||||
		repository: repo,
 | 
							repository: repo,
 | 
				
			||||||
		revisionStore: &revisionStore{
 | 
							revisionStore: &revisionStore{
 | 
				
			||||||
			ctx:        repo.ctx,
 | 
								ctx:        ctx,
 | 
				
			||||||
			repository: repo,
 | 
								repository: repo,
 | 
				
			||||||
			blobStore: &linkedBlobStore{
 | 
								blobStore: &linkedBlobStore{
 | 
				
			||||||
				ctx:        repo.ctx,
 | 
									ctx:        ctx,
 | 
				
			||||||
				blobStore:  repo.blobStore,
 | 
									blobStore:  repo.blobStore,
 | 
				
			||||||
				repository: repo,
 | 
									repository: repo,
 | 
				
			||||||
				statter: &linkedBlobStatter{
 | 
									statter: &linkedBlobStatter{
 | 
				
			||||||
| 
						 | 
					@ -122,11 +122,21 @@ func (repo *repository) Manifests() distribution.ManifestService {
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		tagStore: &tagStore{
 | 
							tagStore: &tagStore{
 | 
				
			||||||
			ctx:        repo.ctx,
 | 
								ctx:        ctx,
 | 
				
			||||||
			repository: repo,
 | 
								repository: repo,
 | 
				
			||||||
			blobStore:  repo.registry.blobStore,
 | 
								blobStore:  repo.registry.blobStore,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Apply options
 | 
				
			||||||
 | 
						for _, option := range options {
 | 
				
			||||||
 | 
							err := option(ms)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ms, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Blobs returns an instance of the BlobStore. Instantiation is cheap and
 | 
					// Blobs returns an instance of the BlobStore. Instantiation is cheap and
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue