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  }