forked from TrueCloudLab/distribution
Merge pull request #893 from aaronlehmann/functional-opts
Functional options for NewRegistryWithDriver
This commit is contained in:
commit
0189e8c218
8 changed files with 145 additions and 46 deletions
|
@ -118,13 +118,18 @@ func NewApp(ctx context.Context, configuration configuration.Configuration) *App
|
|||
app.configureRedis(&configuration)
|
||||
app.configureLogHook(&configuration)
|
||||
|
||||
options := []storage.RegistryOption{}
|
||||
|
||||
if app.isCache {
|
||||
options = append(options, storage.DisableDigestResumption)
|
||||
}
|
||||
|
||||
// configure deletion
|
||||
var deleteEnabled bool
|
||||
if d, ok := configuration.Storage["delete"]; ok {
|
||||
e, ok := d["enabled"]
|
||||
if ok {
|
||||
if deleteEnabled, ok = e.(bool); !ok {
|
||||
deleteEnabled = false
|
||||
if deleteEnabled, ok := e.(bool); ok && deleteEnabled {
|
||||
options = append(options, storage.EnableDelete)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -139,10 +144,11 @@ func NewApp(ctx context.Context, configuration configuration.Configuration) *App
|
|||
default:
|
||||
panic(fmt.Sprintf("invalid type for redirect config: %#v", redirectConfig))
|
||||
}
|
||||
|
||||
if redirectDisabled {
|
||||
ctxu.GetLogger(app).Infof("backend redirection disabled")
|
||||
}
|
||||
}
|
||||
if redirectDisabled {
|
||||
ctxu.GetLogger(app).Infof("backend redirection disabled")
|
||||
} else {
|
||||
options = append(options, storage.EnableRedirect)
|
||||
}
|
||||
|
||||
// configure storage caches
|
||||
|
@ -158,10 +164,20 @@ func NewApp(ctx context.Context, configuration configuration.Configuration) *App
|
|||
if app.redis == nil {
|
||||
panic("redis configuration required to use for layerinfo cache")
|
||||
}
|
||||
app.registry = storage.NewRegistryWithDriver(app, app.driver, rediscache.NewRedisBlobDescriptorCacheProvider(app.redis), deleteEnabled, !redirectDisabled, app.isCache)
|
||||
cacheProvider := rediscache.NewRedisBlobDescriptorCacheProvider(app.redis)
|
||||
localOptions := append(options, storage.BlobDescriptorCacheProvider(cacheProvider))
|
||||
app.registry, err = storage.NewRegistry(app, app.driver, localOptions...)
|
||||
if err != nil {
|
||||
panic("could not create registry: " + err.Error())
|
||||
}
|
||||
ctxu.GetLogger(app).Infof("using redis blob descriptor cache")
|
||||
case "inmemory":
|
||||
app.registry = storage.NewRegistryWithDriver(app, app.driver, memorycache.NewInMemoryBlobDescriptorCacheProvider(), deleteEnabled, !redirectDisabled, app.isCache)
|
||||
cacheProvider := memorycache.NewInMemoryBlobDescriptorCacheProvider()
|
||||
localOptions := append(options, storage.BlobDescriptorCacheProvider(cacheProvider))
|
||||
app.registry, err = storage.NewRegistry(app, app.driver, localOptions...)
|
||||
if err != nil {
|
||||
panic("could not create registry: " + err.Error())
|
||||
}
|
||||
ctxu.GetLogger(app).Infof("using inmemory blob descriptor cache")
|
||||
default:
|
||||
if v != "" {
|
||||
|
@ -172,7 +188,10 @@ func NewApp(ctx context.Context, configuration configuration.Configuration) *App
|
|||
|
||||
if app.registry == nil {
|
||||
// configure the registry if no cache section is available.
|
||||
app.registry = storage.NewRegistryWithDriver(app.Context, app.driver, nil, deleteEnabled, !redirectDisabled, app.isCache)
|
||||
app.registry, err = storage.NewRegistry(app.Context, app.driver, options...)
|
||||
if err != nil {
|
||||
panic("could not create registry: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
app.registry, err = applyRegistryMiddleware(app.Context, app.registry, configuration.Middleware["registry"])
|
||||
|
|
|
@ -26,12 +26,16 @@ import (
|
|||
func TestAppDispatcher(t *testing.T) {
|
||||
driver := inmemory.New()
|
||||
ctx := context.Background()
|
||||
registry, err := storage.NewRegistry(ctx, driver, storage.BlobDescriptorCacheProvider(memorycache.NewInMemoryBlobDescriptorCacheProvider()), storage.EnableDelete, storage.EnableRedirect)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating registry: %v", err)
|
||||
}
|
||||
app := &App{
|
||||
Config: configuration.Configuration{},
|
||||
Context: ctx,
|
||||
router: v2.Router(),
|
||||
driver: driver,
|
||||
registry: storage.NewRegistryWithDriver(ctx, driver, memorycache.NewInMemoryBlobDescriptorCacheProvider(), true, true, false),
|
||||
registry: registry,
|
||||
}
|
||||
server := httptest.NewServer(app)
|
||||
router := v2.Router()
|
||||
|
|
|
@ -80,13 +80,19 @@ func (te testEnv) RemoteStats() *map[string]int {
|
|||
func makeTestEnv(t *testing.T, name string) testEnv {
|
||||
ctx := context.Background()
|
||||
|
||||
localRegistry := storage.NewRegistryWithDriver(ctx, inmemory.New(), memory.NewInMemoryBlobDescriptorCacheProvider(), false, true, true)
|
||||
localRegistry, err := storage.NewRegistry(ctx, inmemory.New(), storage.BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), storage.EnableRedirect, storage.DisableDigestResumption)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating registry: %v", err)
|
||||
}
|
||||
localRepo, err := localRegistry.Repository(ctx, name)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error getting repo: %v", err)
|
||||
}
|
||||
|
||||
truthRegistry := storage.NewRegistryWithDriver(ctx, inmemory.New(), memory.NewInMemoryBlobDescriptorCacheProvider(), false, false, false)
|
||||
truthRegistry, err := storage.NewRegistry(ctx, inmemory.New(), storage.BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()))
|
||||
if err != nil {
|
||||
t.Fatalf("error creating registry: %v", err)
|
||||
}
|
||||
truthRepo, err := truthRegistry.Repository(ctx, name)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error getting repo: %v", err)
|
||||
|
|
|
@ -73,7 +73,10 @@ func (sm statsManifest) Tags() ([]string, error) {
|
|||
|
||||
func newManifestStoreTestEnv(t *testing.T, name, tag string) *manifestStoreTestEnv {
|
||||
ctx := context.Background()
|
||||
truthRegistry := storage.NewRegistryWithDriver(ctx, inmemory.New(), memory.NewInMemoryBlobDescriptorCacheProvider(), false, false, false)
|
||||
truthRegistry, err := storage.NewRegistry(ctx, inmemory.New(), storage.BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()))
|
||||
if err != nil {
|
||||
t.Fatalf("error creating registry: %v", err)
|
||||
}
|
||||
truthRepo, err := truthRegistry.Repository(ctx, name)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error getting repo: %v", err)
|
||||
|
@ -92,7 +95,10 @@ func newManifestStoreTestEnv(t *testing.T, name, tag string) *manifestStoreTestE
|
|||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
localRegistry := storage.NewRegistryWithDriver(ctx, inmemory.New(), memory.NewInMemoryBlobDescriptorCacheProvider(), false, true, true)
|
||||
localRegistry, err := storage.NewRegistry(ctx, inmemory.New(), storage.BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), storage.EnableRedirect, storage.DisableDigestResumption)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating registry: %v", err)
|
||||
}
|
||||
localRepo, err := localRegistry.Repository(ctx, name)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error getting repo: %v", err)
|
||||
|
|
|
@ -33,7 +33,10 @@ func TestSimpleBlobUpload(t *testing.T) {
|
|||
ctx := context.Background()
|
||||
imageName := "foo/bar"
|
||||
driver := inmemory.New()
|
||||
registry := NewRegistryWithDriver(ctx, driver, memory.NewInMemoryBlobDescriptorCacheProvider(), true, true, false)
|
||||
registry, err := NewRegistry(ctx, driver, BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), EnableDelete, EnableRedirect)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating registry: %v", err)
|
||||
}
|
||||
repository, err := registry.Repository(ctx, imageName)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error getting repo: %v", err)
|
||||
|
@ -193,7 +196,10 @@ func TestSimpleBlobUpload(t *testing.T) {
|
|||
}
|
||||
|
||||
// Reuse state to test delete with a delete-disabled registry
|
||||
registry = NewRegistryWithDriver(ctx, driver, memory.NewInMemoryBlobDescriptorCacheProvider(), false, true, false)
|
||||
registry, err = NewRegistry(ctx, driver, BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), EnableRedirect)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating registry: %v", err)
|
||||
}
|
||||
repository, err = registry.Repository(ctx, imageName)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error getting repo: %v", err)
|
||||
|
@ -212,7 +218,10 @@ func TestSimpleBlobRead(t *testing.T) {
|
|||
ctx := context.Background()
|
||||
imageName := "foo/bar"
|
||||
driver := inmemory.New()
|
||||
registry := NewRegistryWithDriver(ctx, driver, memory.NewInMemoryBlobDescriptorCacheProvider(), true, true, false)
|
||||
registry, err := NewRegistry(ctx, driver, BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), EnableDelete, EnableRedirect)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating registry: %v", err)
|
||||
}
|
||||
repository, err := registry.Repository(ctx, imageName)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error getting repo: %v", err)
|
||||
|
@ -316,7 +325,10 @@ func TestLayerUploadZeroLength(t *testing.T) {
|
|||
ctx := context.Background()
|
||||
imageName := "foo/bar"
|
||||
driver := inmemory.New()
|
||||
registry := NewRegistryWithDriver(ctx, driver, memory.NewInMemoryBlobDescriptorCacheProvider(), true, true, false)
|
||||
registry, err := NewRegistry(ctx, driver, BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), EnableDelete, EnableRedirect)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating registry: %v", err)
|
||||
}
|
||||
repository, err := registry.Repository(ctx, imageName)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error getting repo: %v", err)
|
||||
|
|
|
@ -22,7 +22,10 @@ func setupFS(t *testing.T) *setupEnv {
|
|||
d := inmemory.New()
|
||||
c := []byte("")
|
||||
ctx := context.Background()
|
||||
registry := NewRegistryWithDriver(ctx, d, memory.NewInMemoryBlobDescriptorCacheProvider(), false, true, false)
|
||||
registry, err := NewRegistry(ctx, d, BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), EnableRedirect)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating registry: %v", err)
|
||||
}
|
||||
rootpath, _ := pathFor(repositoriesRootPathSpec{})
|
||||
|
||||
repos := []string{
|
||||
|
|
|
@ -29,7 +29,10 @@ type manifestStoreTestEnv struct {
|
|||
func newManifestStoreTestEnv(t *testing.T, name, tag string) *manifestStoreTestEnv {
|
||||
ctx := context.Background()
|
||||
driver := inmemory.New()
|
||||
registry := NewRegistryWithDriver(ctx, driver, memory.NewInMemoryBlobDescriptorCacheProvider(), true, true, false)
|
||||
registry, err := NewRegistry(ctx, driver, BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), EnableDelete, EnableRedirect)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating registry: %v", err)
|
||||
}
|
||||
|
||||
repo, err := registry.Repository(ctx, name)
|
||||
if err != nil {
|
||||
|
@ -348,7 +351,10 @@ func TestManifestStorage(t *testing.T) {
|
|||
t.Errorf("Deleted manifest get returned non-nil")
|
||||
}
|
||||
|
||||
r := NewRegistryWithDriver(ctx, env.driver, memory.NewInMemoryBlobDescriptorCacheProvider(), false, true, false)
|
||||
r, err := NewRegistry(ctx, env.driver, BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), EnableRedirect)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating registry: %v", err)
|
||||
}
|
||||
repo, err := r.Repository(ctx, env.name)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error getting repo: %v", err)
|
||||
|
|
|
@ -12,28 +12,65 @@ import (
|
|||
// package. All instances should descend from this object.
|
||||
type registry struct {
|
||||
blobStore *blobStore
|
||||
blobServer distribution.BlobServer
|
||||
statter distribution.BlobStatter // global statter service.
|
||||
blobServer *blobServer
|
||||
statter *blobStatter // global statter service.
|
||||
blobDescriptorCacheProvider cache.BlobDescriptorCacheProvider
|
||||
deleteEnabled bool
|
||||
resumableDigestEnabled bool
|
||||
}
|
||||
|
||||
// NewRegistryWithDriver creates a new registry instance from the provided
|
||||
// driver. The resulting registry may be shared by multiple goroutines but is
|
||||
// cheap to allocate. If redirect is true, the backend blob server will
|
||||
// attempt to use (StorageDriver).URLFor to serve all blobs.
|
||||
//
|
||||
// TODO(stevvooe): This function signature is getting very out of hand. Move to
|
||||
// functional options for instance configuration.
|
||||
func NewRegistryWithDriver(ctx context.Context, driver storagedriver.StorageDriver, blobDescriptorCacheProvider cache.BlobDescriptorCacheProvider, deleteEnabled bool, redirect bool, isCache bool) distribution.Namespace {
|
||||
// create global statter, with cache.
|
||||
var statter distribution.BlobDescriptorService = &blobStatter{
|
||||
driver: driver,
|
||||
}
|
||||
// RegistryOption is the type used for functional options for NewRegistry.
|
||||
type RegistryOption func(*registry) error
|
||||
|
||||
if blobDescriptorCacheProvider != nil {
|
||||
statter = cache.NewCachedBlobStatter(blobDescriptorCacheProvider, statter)
|
||||
// EnableRedirect is a functional option for NewRegistry. It causes the backend
|
||||
// blob server to attempt using (StorageDriver).URLFor to serve all blobs.
|
||||
func EnableRedirect(registry *registry) error {
|
||||
registry.blobServer.redirect = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// EnableDelete is a functional option for NewRegistry. It enables deletion on
|
||||
// the registry.
|
||||
func EnableDelete(registry *registry) error {
|
||||
registry.deleteEnabled = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// DisableDigestResumption is a functional option for NewRegistry. It should be
|
||||
// used if the registry is acting as a caching proxy.
|
||||
func DisableDigestResumption(registry *registry) error {
|
||||
registry.resumableDigestEnabled = false
|
||||
return nil
|
||||
}
|
||||
|
||||
// BlobDescriptorCacheProvider returns a functional option for
|
||||
// NewRegistry. It creates a cached blob statter for use by the
|
||||
// registry.
|
||||
func BlobDescriptorCacheProvider(blobDescriptorCacheProvider cache.BlobDescriptorCacheProvider) RegistryOption {
|
||||
// TODO(aaronl): The duplication of statter across several objects is
|
||||
// ugly, and prevents us from using interface types in the registry
|
||||
// struct. Ideally, blobStore and blobServer should be lazily
|
||||
// initialized, and use the current value of
|
||||
// blobDescriptorCacheProvider.
|
||||
return func(registry *registry) error {
|
||||
if blobDescriptorCacheProvider != nil {
|
||||
statter := cache.NewCachedBlobStatter(blobDescriptorCacheProvider, registry.statter)
|
||||
registry.blobStore.statter = statter
|
||||
registry.blobServer.statter = statter
|
||||
registry.blobDescriptorCacheProvider = blobDescriptorCacheProvider
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// NewRegistry creates a new registry instance from the provided driver. The
|
||||
// resulting registry may be shared by multiple goroutines but is cheap to
|
||||
// allocate. If the Redirect option is specified, the backend blob server will
|
||||
// attempt to use (StorageDriver).URLFor to serve all blobs.
|
||||
func NewRegistry(ctx context.Context, driver storagedriver.StorageDriver, options ...RegistryOption) (distribution.Namespace, error) {
|
||||
// create global statter
|
||||
statter := &blobStatter{
|
||||
driver: driver,
|
||||
}
|
||||
|
||||
bs := &blobStore{
|
||||
|
@ -41,18 +78,24 @@ func NewRegistryWithDriver(ctx context.Context, driver storagedriver.StorageDriv
|
|||
statter: statter,
|
||||
}
|
||||
|
||||
return ®istry{
|
||||
registry := ®istry{
|
||||
blobStore: bs,
|
||||
blobServer: &blobServer{
|
||||
driver: driver,
|
||||
statter: statter,
|
||||
pathFn: bs.path,
|
||||
redirect: redirect,
|
||||
driver: driver,
|
||||
statter: statter,
|
||||
pathFn: bs.path,
|
||||
},
|
||||
blobDescriptorCacheProvider: blobDescriptorCacheProvider,
|
||||
deleteEnabled: deleteEnabled,
|
||||
resumableDigestEnabled: !isCache,
|
||||
statter: statter,
|
||||
resumableDigestEnabled: true,
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
if err := option(registry); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return registry, nil
|
||||
}
|
||||
|
||||
// Scope returns the namespace scope for a registry. The registry
|
||||
|
|
Loading…
Reference in a new issue