don't panic during a request when configuring repository middleware. Return a 500 with an appropriate error

Signed-off-by: David Lawrence <david.lawrence@docker.com> (github: endophage)
This commit is contained in:
David Lawrence 2015-03-09 10:55:52 -07:00
parent b5a63d75ea
commit 3853e66f4b
3 changed files with 53 additions and 26 deletions

View file

@ -300,7 +300,7 @@ type Middleware struct {
// Name the middleware registers itself as // Name the middleware registers itself as
Name string `yaml:"name"` Name string `yaml:"name"`
// Flag to disable middleware easily // Flag to disable middleware easily
Disabled bool `yaml:"Disabled,omitempty"` Disabled bool `yaml:"disabled,omitempty"`
// Map of parameters that will be passed to the middleware's initialization function // Map of parameters that will be passed to the middleware's initialization function
Options Parameters `yaml:"options"` Options Parameters `yaml:"options"`
} }

View file

@ -89,16 +89,17 @@ func NewApp(ctx context.Context, configuration configuration.Configuration) *App
// a health check. // a health check.
panic(err) panic(err)
} }
app.driver, err = applyStorageMiddleware(app.driver, configuration.Middleware["storage"])
if err != nil {
panic(err)
}
app.configureEvents(&configuration) app.configureEvents(&configuration)
app.registry = storage.NewRegistryWithDriver(app.driver) app.registry = storage.NewRegistryWithDriver(app.driver)
for _, mw := range configuration.Middleware["registry"] { app.registry, err = applyRegistryMiddleware(app.registry, configuration.Middleware["registry"])
rmw, err := registrymiddleware.Get(mw.Name, mw.Options, app.registry) if err != nil {
if err != nil { panic(err)
panic(fmt.Sprintf("unable to configure registry middleware (%s): %s", mw.Name, err))
}
app.registry = rmw
} }
authType := configuration.Auth.Type() authType := configuration.Auth.Type()
@ -111,14 +112,6 @@ func NewApp(ctx context.Context, configuration configuration.Configuration) *App
app.accessController = accessController app.accessController = accessController
} }
for _, mw := range configuration.Middleware["storage"] {
smw, err := storagemiddleware.Get(mw.Name, mw.Options, app.driver)
if err != nil {
panic(fmt.Sprintf("unable to configure storage middleware (%s): %v", mw.Name, err))
}
app.driver = smw
}
return app return app
} }
@ -258,12 +251,13 @@ func (app *App) dispatcher(dispatch dispatchFunc) http.Handler {
repository, repository,
app.eventBridge(context, r)) app.eventBridge(context, r))
for _, mw := range app.Config.Middleware["repository"] { context.Repository, err = applyRepoMiddleware(context.Repository, app.Config.Middleware["repository"])
rmw, err := repositorymiddleware.Get(mw.Name, mw.Options, context.Repository) if err != nil {
if err != nil { ctxu.GetLogger(context).Errorf("error initializing repository middleware: %v", err)
panic(fmt.Sprintf("unable to configure repository middleware (%s): %s", mw.Name, err)) context.Errors.Push(v2.ErrorCodeUnknown, err)
} w.WriteHeader(http.StatusInternalServerError)
context.Repository = rmw serveJSON(w, context.Errors)
return
} }
} }
@ -433,3 +427,40 @@ func appendAccessRecords(records []auth.Access, method string, repo string) []au
} }
return records return records
} }
// applyRegistryMiddleware wraps a registry instance with the configured middlewares
func applyRegistryMiddleware(registry distribution.Registry, middlewares []configuration.Middleware) (distribution.Registry, error) {
for _, mw := range middlewares {
rmw, err := registrymiddleware.Get(mw.Name, mw.Options, registry)
if err != nil {
return nil, fmt.Errorf("unable to configure registry middleware (%s): %s", mw.Name, err)
}
registry = rmw
}
return registry, nil
}
// applyRepoMiddleware wraps a repository with the configured middlewares
func applyRepoMiddleware(repository distribution.Repository, middlewares []configuration.Middleware) (distribution.Repository, error) {
for _, mw := range middlewares {
rmw, err := repositorymiddleware.Get(mw.Name, mw.Options, repository)
if err != nil {
return nil, err
}
repository = rmw
}
return repository, nil
}
// applyStorageMiddleware wraps a storage driver with the configured middlewares
func applyStorageMiddleware(driver storagedriver.StorageDriver, middlewares []configuration.Middleware) (storagedriver.StorageDriver, error) {
for _, mw := range middlewares {
smw, err := storagemiddleware.Get(mw.Name, mw.Options, driver)
if err != nil {
return nil, fmt.Errorf("unable to configure storage middleware (%s): %v", mw.Name, err)
}
driver = smw
}
return driver, nil
}

View file

@ -18,10 +18,6 @@ type layerReader struct {
var _ distribution.Layer = &layerReader{} var _ distribution.Layer = &layerReader{}
func (lr *layerReader) Path() string {
return lr.path
}
func (lr *layerReader) Digest() digest.Digest { func (lr *layerReader) Digest() digest.Digest {
return lr.digest return lr.digest
} }
@ -42,7 +38,7 @@ func (lr *layerReader) Close() error {
func (lr *layerReader) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (lr *layerReader) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Docker-Content-Digest", lr.digest.String()) w.Header().Set("Docker-Content-Digest", lr.digest.String())
if url, err := lr.fileReader.driver.URLFor(lr.Path(), map[string]interface{}{}); err == nil { if url, err := lr.fileReader.driver.URLFor(lr.path, map[string]interface{}{}); err == nil {
http.Redirect(w, r, url, http.StatusTemporaryRedirect) http.Redirect(w, r, url, http.StatusTemporaryRedirect)
} }
http.ServeContent(w, r, lr.digest.String(), lr.CreatedAt(), lr) http.ServeContent(w, r, lr.digest.String(), lr.CreatedAt(), lr)