ed3ecfdccb
Several error codes are generally useful but tied to the v2 specification definitions. This change moves these error code definitions into the common package for use by the health package, which is not tied to the v2 API. Signed-off-by: Stephen J Day <stephen.day@docker.com>
155 lines
3.7 KiB
Go
155 lines
3.7 KiB
Go
package proxy
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/docker/distribution"
|
|
"github.com/docker/distribution/context"
|
|
"github.com/docker/distribution/digest"
|
|
"github.com/docker/distribution/manifest"
|
|
"github.com/docker/distribution/registry/api/errcode"
|
|
"github.com/docker/distribution/registry/client"
|
|
"github.com/docker/distribution/registry/proxy/scheduler"
|
|
)
|
|
|
|
// todo(richardscothern): from cache control header or config
|
|
const repositoryTTL = time.Duration(24 * 7 * time.Hour)
|
|
|
|
type proxyManifestStore struct {
|
|
ctx context.Context
|
|
localManifests distribution.ManifestService
|
|
remoteManifests distribution.ManifestService
|
|
repositoryName string
|
|
scheduler *scheduler.TTLExpirationScheduler
|
|
}
|
|
|
|
var _ distribution.ManifestService = &proxyManifestStore{}
|
|
|
|
func (pms proxyManifestStore) Exists(dgst digest.Digest) (bool, error) {
|
|
exists, err := pms.localManifests.Exists(dgst)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
if exists {
|
|
return true, nil
|
|
}
|
|
|
|
return pms.remoteManifests.Exists(dgst)
|
|
}
|
|
|
|
func (pms proxyManifestStore) Get(dgst digest.Digest) (*manifest.SignedManifest, error) {
|
|
sm, err := pms.localManifests.Get(dgst)
|
|
if err == nil {
|
|
proxyMetrics.ManifestPush(uint64(len(sm.Raw)))
|
|
return sm, err
|
|
}
|
|
|
|
sm, err = pms.remoteManifests.Get(dgst)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
proxyMetrics.ManifestPull(uint64(len(sm.Raw)))
|
|
err = pms.localManifests.Put(sm)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Schedule the repo for removal
|
|
pms.scheduler.AddManifest(pms.repositoryName, repositoryTTL)
|
|
|
|
// Ensure the manifest blob is cleaned up
|
|
pms.scheduler.AddBlob(dgst.String(), repositoryTTL)
|
|
|
|
proxyMetrics.ManifestPush(uint64(len(sm.Raw)))
|
|
|
|
return sm, err
|
|
}
|
|
|
|
func (pms proxyManifestStore) Tags() ([]string, error) {
|
|
return pms.localManifests.Tags()
|
|
}
|
|
|
|
func (pms proxyManifestStore) ExistsByTag(tag string) (bool, error) {
|
|
exists, err := pms.localManifests.ExistsByTag(tag)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
if exists {
|
|
return true, nil
|
|
}
|
|
|
|
return pms.remoteManifests.ExistsByTag(tag)
|
|
}
|
|
|
|
func (pms proxyManifestStore) GetByTag(tag string, options ...distribution.ManifestServiceOption) (*manifest.SignedManifest, error) {
|
|
var localDigest digest.Digest
|
|
|
|
localManifest, err := pms.localManifests.GetByTag(tag, options...)
|
|
switch err.(type) {
|
|
case distribution.ErrManifestUnknown, distribution.ErrManifestUnknownRevision:
|
|
goto fromremote
|
|
case nil:
|
|
break
|
|
default:
|
|
return nil, err
|
|
}
|
|
|
|
localDigest, err = manifestDigest(localManifest)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
fromremote:
|
|
var sm *manifest.SignedManifest
|
|
sm, err = pms.remoteManifests.GetByTag(tag, client.AddEtagToTag(tag, localDigest.String()))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if sm == nil {
|
|
context.GetLogger(pms.ctx).Debugf("Local manifest for %q is latest, dgst=%s", tag, localDigest.String())
|
|
return localManifest, nil
|
|
}
|
|
context.GetLogger(pms.ctx).Debugf("Updated manifest for %q, dgst=%s", tag, localDigest.String())
|
|
|
|
err = pms.localManifests.Put(sm)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
dgst, err := manifestDigest(sm)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
pms.scheduler.AddBlob(dgst.String(), repositoryTTL)
|
|
pms.scheduler.AddManifest(pms.repositoryName, repositoryTTL)
|
|
|
|
proxyMetrics.ManifestPull(uint64(len(sm.Raw)))
|
|
proxyMetrics.ManifestPush(uint64(len(sm.Raw)))
|
|
|
|
return sm, err
|
|
}
|
|
|
|
func manifestDigest(sm *manifest.SignedManifest) (digest.Digest, error) {
|
|
payload, err := sm.Payload()
|
|
if err != nil {
|
|
return "", err
|
|
|
|
}
|
|
|
|
dgst, err := digest.FromBytes(payload)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return dgst, nil
|
|
}
|
|
|
|
func (pms proxyManifestStore) Put(manifest *manifest.SignedManifest) error {
|
|
return errcode.ErrorCodeUnsupported
|
|
}
|
|
|
|
func (pms proxyManifestStore) Delete(dgst digest.Digest) error {
|
|
return errcode.ErrorCodeUnsupported
|
|
}
|