2015-07-29 18:12:01 +00:00
|
|
|
package proxy
|
|
|
|
|
|
|
|
import (
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/docker/distribution"
|
|
|
|
"github.com/docker/distribution/context"
|
|
|
|
"github.com/docker/distribution/digest"
|
2015-08-21 04:24:30 +00:00
|
|
|
"github.com/docker/distribution/manifest/schema1"
|
2015-07-29 18:12:01 +00:00
|
|
|
"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)
|
|
|
|
}
|
|
|
|
|
2015-08-21 04:24:30 +00:00
|
|
|
func (pms proxyManifestStore) Get(dgst digest.Digest) (*schema1.SignedManifest, error) {
|
2015-07-29 18:12:01 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2015-08-21 04:24:30 +00:00
|
|
|
func (pms proxyManifestStore) GetByTag(tag string, options ...distribution.ManifestServiceOption) (*schema1.SignedManifest, error) {
|
2015-07-29 18:12:01 +00:00
|
|
|
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:
|
2015-08-21 04:24:30 +00:00
|
|
|
var sm *schema1.SignedManifest
|
2015-07-29 18:12:01 +00:00
|
|
|
sm, err = pms.remoteManifests.GetByTag(tag, client.AddEtagToTag(tag, localDigest.String()))
|
2015-09-18 18:00:44 +00:00
|
|
|
if err != nil && err != distribution.ErrManifestNotModified {
|
2015-07-29 18:12:01 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2015-09-18 18:00:44 +00:00
|
|
|
if err == distribution.ErrManifestNotModified {
|
2015-07-29 18:12:01 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2015-08-21 04:24:30 +00:00
|
|
|
func manifestDigest(sm *schema1.SignedManifest) (digest.Digest, error) {
|
2015-07-29 18:12:01 +00:00
|
|
|
payload, err := sm.Payload()
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
dgst, err := digest.FromBytes(payload)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
return dgst, nil
|
|
|
|
}
|
|
|
|
|
2015-08-21 04:24:30 +00:00
|
|
|
func (pms proxyManifestStore) Put(manifest *schema1.SignedManifest) error {
|
2015-08-11 18:00:30 +00:00
|
|
|
return distribution.ErrUnsupported
|
2015-07-29 18:12:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (pms proxyManifestStore) Delete(dgst digest.Digest) error {
|
2015-08-11 18:00:30 +00:00
|
|
|
return distribution.ErrUnsupported
|
2015-07-29 18:12:01 +00:00
|
|
|
}
|