distribution/docs/middleware/manifeststore.go
2016-09-28 14:25:04 -07:00

130 lines
4.8 KiB
Go

package middleware
import (
"fmt"
middlewareErrors "github.com/docker/dhe-deploy/registry/middleware/errors"
"github.com/docker/distribution"
"github.com/docker/distribution/context"
"github.com/docker/distribution/digest"
"github.com/docker/distribution/manifest/manifestlist"
"github.com/docker/distribution/manifest/schema1"
"github.com/docker/distribution/manifest/schema2"
"github.com/docker/distribution/registry/handlers"
"github.com/docker/libtrust"
)
// manifestStore provides an alternative backing mechanism for manifests.
// It must implement the ManifestService to store manifests and
// ManifestEnumerator for garbage collection and listing
type manifestStore struct {
// useFilesystemStore is a flag which determines whether to use the default
// filesystem service for all read actions. We need to fall back to the
// filesystem for checking whether manifests exist if the metadata store
// is still syncing.
//
// TODO (tonyhb) Determine whether the metadata store is faster; if it's
// not we can remove this flag and always use distribution's filesystem
// store for read operations
useFilesystemStore bool
app *handlers.App
ctx context.Context
store Store
signingKey libtrust.PrivateKey
repo distribution.Repository
blobService distribution.ManifestService
}
func (m *manifestStore) Exists(ctx context.Context, dgst digest.Digest) (bool, error) {
return m.blobService.Exists(ctx, dgst)
}
// Get retrieves the manifest specified by the given digest for a repo.
//
// Note that the middleware itself verifies that the manifest is valid;
// the storage backend should only marshal and unmarshal into the correct type.
func (m *manifestStore) Get(ctx context.Context, dgst digest.Digest, options ...distribution.ManifestServiceOption) (distribution.Manifest, error) {
return m.blobService.Get(ctx, dgst, options...)
}
// Put creates or updates the given manifest returning the manifest digest
func (m *manifestStore) Put(ctx context.Context, manifest distribution.Manifest, options ...distribution.ManifestServiceOption) (d digest.Digest, err error) {
// First, ensure we write the manifest to the filesystem as per standard
// distribution code.
if d, err = m.blobService.Put(ctx, manifest, options...); err != nil {
context.GetLoggerWithField(ctx, "err", err).Error("error savng manifest to blobstore")
return d, err
}
// NOTE: we're not allowing skipDependencyVerification here.
//
// skipDependencyVerification is ONLY used when registry is set up as a
// pull-through cache (proxy). In these circumstances this middleware
// should not be used, therefore this verification implementation always
// verifies blobs.
//
// This is the only difference in implementation with storage's
// manifestStore{}
switch manifest.(type) {
case *schema1.SignedManifest:
err = m.VerifyV1(ctx, manifest.(*schema1.SignedManifest))
case *schema2.DeserializedManifest:
ctx, err = m.VerifyV2(ctx, manifest.(*schema2.DeserializedManifest))
case *manifestlist.DeserializedManifestList:
err = m.VerifyList(ctx, manifest.(*manifestlist.DeserializedManifestList))
default:
err = fmt.Errorf("Unknown manifest type: %T", manifest)
}
if err != nil {
return
}
// Our storage service needs the digest of the manifest in order to
// store the manifest under the correct key.
_, data, err := manifest.Payload()
if err != nil {
return
}
// NOTE that for v1 manifests .Payload() returns the entire manifest including
// the randomly generated signature. Digests must always be calculated on the
// canonical manifest without signatures.
if man, ok := manifest.(*schema1.SignedManifest); ok {
data = man.Canonical
}
dgst := digest.FromBytes(data)
err = m.store.PutManifest(ctx, m.repo.Named().String(), string(dgst), manifest)
return dgst, err
}
// Delete removes the manifest specified by the given digest.
func (m *manifestStore) Delete(ctx context.Context, dgst digest.Digest) error {
key := m.key(dgst)
// First delete from the manifest store in rethinkDB. We can silently ignore
// ErrNotFound issues - when deleting a tag from DTR's API the manifest
// will already be removed from the tagstore if no tags reference it.
// Unfortunately, this API call cannot delete manifests from the blobstore
// so this will be called directly.
_, err := m.store.GetManifest(ctx, key)
if err != nil && err != middlewareErrors.ErrNotFound {
context.GetLoggerWithField(ctx, "err", err).Error("error getting manifest from metadata store")
return err
}
if err := m.store.DeleteManifest(ctx, key); err != nil {
context.GetLoggerWithField(ctx, "err", err).Error("error deleting manifest from metadata store")
return err
}
// Delete this within the blobService
return m.blobService.Delete(ctx, dgst)
}
func (m *manifestStore) key(dgst digest.Digest) string {
return m.repo.Named().String() + "@" + string(dgst)
}