github.com/mika/distribution@v2.2.2-0.20160108133430-a75790e3d8e0+incompatible/registry/proxy/proxyregistry.go (about) 1 package proxy 2 3 import ( 4 "net/http" 5 "net/url" 6 7 "github.com/docker/distribution" 8 "github.com/docker/distribution/configuration" 9 "github.com/docker/distribution/context" 10 "github.com/docker/distribution/registry/client" 11 "github.com/docker/distribution/registry/client/auth" 12 "github.com/docker/distribution/registry/client/transport" 13 "github.com/docker/distribution/registry/proxy/scheduler" 14 "github.com/docker/distribution/registry/storage" 15 "github.com/docker/distribution/registry/storage/driver" 16 ) 17 18 // proxyingRegistry fetches content from a remote registry and caches it locally 19 type proxyingRegistry struct { 20 embedded distribution.Namespace // provides local registry functionality 21 22 scheduler *scheduler.TTLExpirationScheduler 23 24 remoteURL string 25 credentialStore auth.CredentialStore 26 challengeManager auth.ChallengeManager 27 } 28 29 // NewRegistryPullThroughCache creates a registry acting as a pull through cache 30 func NewRegistryPullThroughCache(ctx context.Context, registry distribution.Namespace, driver driver.StorageDriver, config configuration.Proxy) (distribution.Namespace, error) { 31 _, err := url.Parse(config.RemoteURL) 32 if err != nil { 33 return nil, err 34 } 35 36 v := storage.NewVacuum(ctx, driver) 37 38 s := scheduler.New(ctx, driver, "/scheduler-state.json") 39 s.OnBlobExpire(func(digest string) error { 40 return v.RemoveBlob(digest) 41 }) 42 s.OnManifestExpire(func(repoName string) error { 43 return v.RemoveRepository(repoName) 44 }) 45 46 err = s.Start() 47 if err != nil { 48 return nil, err 49 } 50 51 challengeManager := auth.NewSimpleChallengeManager() 52 cs, err := ConfigureAuth(config.RemoteURL, config.Username, config.Password, challengeManager) 53 if err != nil { 54 return nil, err 55 } 56 57 return &proxyingRegistry{ 58 embedded: registry, 59 scheduler: s, 60 challengeManager: challengeManager, 61 credentialStore: cs, 62 remoteURL: config.RemoteURL, 63 }, nil 64 } 65 66 func (pr *proxyingRegistry) Scope() distribution.Scope { 67 return distribution.GlobalScope 68 } 69 70 func (pr *proxyingRegistry) Repositories(ctx context.Context, repos []string, last string) (n int, err error) { 71 return pr.embedded.Repositories(ctx, repos, last) 72 } 73 74 func (pr *proxyingRegistry) Repository(ctx context.Context, name string) (distribution.Repository, error) { 75 tr := transport.NewTransport(http.DefaultTransport, 76 auth.NewAuthorizer(pr.challengeManager, auth.NewTokenHandler(http.DefaultTransport, pr.credentialStore, name, "pull"))) 77 78 localRepo, err := pr.embedded.Repository(ctx, name) 79 if err != nil { 80 return nil, err 81 } 82 localManifests, err := localRepo.Manifests(ctx, storage.SkipLayerVerification()) 83 if err != nil { 84 return nil, err 85 } 86 87 remoteRepo, err := client.NewRepository(ctx, name, pr.remoteURL, tr) 88 if err != nil { 89 return nil, err 90 } 91 92 remoteManifests, err := remoteRepo.Manifests(ctx) 93 if err != nil { 94 return nil, err 95 } 96 97 return &proxiedRepository{ 98 blobStore: &proxyBlobStore{ 99 localStore: localRepo.Blobs(ctx), 100 remoteStore: remoteRepo.Blobs(ctx), 101 scheduler: pr.scheduler, 102 }, 103 manifests: proxyManifestStore{ 104 repositoryName: name, 105 localManifests: localManifests, // Options? 106 remoteManifests: remoteManifests, 107 ctx: ctx, 108 scheduler: pr.scheduler, 109 }, 110 name: name, 111 tags: proxyTagService{ 112 localTags: localRepo.Tags(ctx), 113 remoteTags: remoteRepo.Tags(ctx), 114 }, 115 }, nil 116 } 117 118 // proxiedRepository uses proxying blob and manifest services to serve content 119 // locally, or pulling it through from a remote and caching it locally if it doesn't 120 // already exist 121 type proxiedRepository struct { 122 blobStore distribution.BlobStore 123 manifests distribution.ManifestService 124 name string 125 tags distribution.TagService 126 } 127 128 func (pr *proxiedRepository) Manifests(ctx context.Context, options ...distribution.ManifestServiceOption) (distribution.ManifestService, error) { 129 return pr.manifests, nil 130 } 131 132 func (pr *proxiedRepository) Blobs(ctx context.Context) distribution.BlobStore { 133 return pr.blobStore 134 } 135 136 func (pr *proxiedRepository) Name() string { 137 return pr.name 138 } 139 140 func (pr *proxiedRepository) Tags(ctx context.Context) distribution.TagService { 141 return pr.tags 142 }