-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add dockerregistry/server.App struct for application-level data #15796
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
package server | ||
|
||
import ( | ||
"net/http" | ||
"os" | ||
|
||
"github.com/docker/distribution" | ||
"github.com/docker/distribution/configuration" | ||
"github.com/docker/distribution/context" | ||
"github.com/docker/distribution/registry/handlers" | ||
storagedriver "github.com/docker/distribution/registry/storage/driver" | ||
|
||
"github.com/openshift/origin/pkg/dockerregistry/server/client" | ||
registryconfig "github.com/openshift/origin/pkg/dockerregistry/server/configuration" | ||
"github.com/openshift/origin/pkg/dockerregistry/server/maxconnections" | ||
) | ||
|
||
// App is a global registry application object. Shared resources can be placed | ||
// on this object that will be accessible from all requests. | ||
type App struct { | ||
// ctx is the parent context. | ||
ctx context.Context | ||
|
||
registryClient client.RegistryClient | ||
extraConfig *registryconfig.Configuration | ||
repositoryConfig repositoryConfig | ||
writeLimiter maxconnections.Limiter | ||
|
||
// driver gives access to the blob store. | ||
// This variable holds the object created by docker/distribution. We | ||
// import it into our namespace because there are no other ways to access | ||
// it. In other cases it is hidden from us. | ||
driver storagedriver.StorageDriver | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could this be called There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I synced this name with the upstream name. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ahh, OK. |
||
|
||
// registry represents a collection of repositories, addressable by name. | ||
// This variable holds the object created by docker/distribution. We | ||
// import it into our namespace because there are no other ways to access | ||
// it. In other cases it is hidden from us. | ||
registry distribution.Namespace | ||
|
||
// cachedLayers is a shared cache of blob digests to repositories that have previously been identified as | ||
// containing that blob. Thread safe and reused by all middleware layers. It contains two kinds of | ||
// associations: | ||
// 1. <blobdigest> <-> <registry>/<namespace>/<name> | ||
// 2. <blobdigest> <-> <namespace>/<name> | ||
// The first associates a blob with a remote repository. Such an entry is set and used by pullthrough | ||
// middleware. The second associates a blob with a local repository. Such a blob is expected to reside on | ||
// local storage. It's set and used by blobDescriptorService middleware. | ||
cachedLayers digestToRepositoryCache | ||
|
||
// quotaEnforcing contains shared caches of quota objects keyed by project | ||
// name. Will be initialized only if the quota is enforced. | ||
// See EnforceQuotaEnvVar. | ||
quotaEnforcing *quotaEnforcingConfig | ||
} | ||
|
||
// NewApp configures the registry application and returns http.Handler for it. | ||
// The program will be terminated if an error happens. | ||
func NewApp(ctx context.Context, registryClient client.RegistryClient, dockerConfig *configuration.Configuration, extraConfig *registryconfig.Configuration, writeLimiter maxconnections.Limiter) http.Handler { | ||
app := &App{ | ||
ctx: ctx, | ||
registryClient: registryClient, | ||
extraConfig: extraConfig, | ||
writeLimiter: writeLimiter, | ||
} | ||
|
||
cache, err := newDigestToRepositoryCache(defaultDigestToRepositoryCacheSize) | ||
if err != nil { | ||
panic(err) | ||
} | ||
app.cachedLayers = cache | ||
|
||
weaveAppIntoConfig(app, dockerConfig) | ||
|
||
repositoryEnabled := false | ||
for _, middleware := range dockerConfig.Middleware["repository"] { | ||
if middleware.Name == middlewareOpenShift { | ||
rc, err := newRepositoryConfig(ctx, middleware.Options) | ||
if err != nil { | ||
context.GetLogger(ctx).Fatalf("error configuring the repository middleware: %s", err) | ||
} | ||
app.repositoryConfig = rc | ||
app.quotaEnforcing = newQuotaEnforcingConfig(ctx, os.Getenv(EnforceQuotaEnvVar), os.Getenv(ProjectCacheTTLEnvVar), middleware.Options) | ||
repositoryEnabled = true | ||
break | ||
} | ||
} | ||
|
||
dockerApp := handlers.NewApp(ctx, dockerConfig) | ||
|
||
if repositoryEnabled { | ||
if app.driver == nil { | ||
context.GetLogger(ctx).Fatalf("configuration error: the storage driver middleware %q is not activated", middlewareOpenShift) | ||
} | ||
|
||
if app.registry == nil { | ||
context.GetLogger(ctx).Fatalf("configuration error: the registry middleware %q is not activated", middlewareOpenShift) | ||
} | ||
} | ||
|
||
// Add a token handling endpoint | ||
if dockerConfig.Auth.Type() == middlewareOpenShift { | ||
tokenRealm, err := TokenRealm(dockerConfig.Auth[middlewareOpenShift]) | ||
if err != nil { | ||
context.GetLogger(dockerApp).Fatalf("error setting up token auth: %s", err) | ||
} | ||
err = dockerApp.NewRoute().Methods("GET").PathPrefix(tokenRealm.Path).Handler(NewTokenHandler(ctx, registryClient)).GetError() | ||
if err != nil { | ||
context.GetLogger(dockerApp).Fatalf("error setting up token endpoint at %q: %v", tokenRealm.Path, err) | ||
} | ||
context.GetLogger(dockerApp).Debugf("configured token endpoint at %q", tokenRealm.String()) | ||
} | ||
|
||
app.registerBlobHandler(dockerApp) | ||
|
||
// Registry extensions endpoint provides extra functionality to handle the image | ||
// signatures. | ||
RegisterSignatureHandler(dockerApp) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit/joke: I need to remember to register next special handler using locally defined closure or something more creative. |
||
|
||
// Registry extensions endpoint provides prometheus metrics. | ||
if extraConfig.Metrics.Enabled { | ||
if len(extraConfig.Metrics.Secret) == 0 { | ||
context.GetLogger(dockerApp).Fatalf("openshift.metrics.secret field cannot be empty when metrics are enabled") | ||
} | ||
RegisterMetricHandler(dockerApp) | ||
} | ||
|
||
// Advertise features supported by OpenShift | ||
if dockerApp.Config.HTTP.Headers == nil { | ||
dockerApp.Config.HTTP.Headers = http.Header{} | ||
} | ||
dockerApp.Config.HTTP.Headers.Set("X-Registry-Supports-Signatures", "1") | ||
|
||
dockerApp.RegisterHealthChecks() | ||
|
||
return dockerApp | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see no need for making this a method of
*App
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having method here feels more natural for me, registerBlobHandler is a part of the application and it uses closure
app.blobDispatcher
.