diff --git a/registry/storage/blobserver.go b/registry/storage/blobserver.go index 2d89ecd8..45f81f53 100644 --- a/registry/storage/blobserver.go +++ b/registry/storage/blobserver.go @@ -36,15 +36,15 @@ func (bs *blobServer) ServeBlob(ctx context.Context, w http.ResponseWriter, r *h redirectURL, err := bs.driver.URLFor(ctx, path, map[string]interface{}{"method": r.Method}) - if err == nil { + switch err.(type) { + case nil: if bs.redirect { // Redirect to storage URL. http.Redirect(w, r, redirectURL, http.StatusTemporaryRedirect) return err } - } - if _, ok := err.(*driver.ErrUnsupportedMethod); ok { + case driver.ErrUnsupportedMethod: // Fallback to serving the content directly. br, err := newFileReader(ctx, bs.driver, path, desc.Size) if err != nil { diff --git a/registry/storage/driver/base/base.go b/registry/storage/driver/base/base.go index 2333bba7..c816d2d6 100644 --- a/registry/storage/driver/base/base.go +++ b/registry/storage/driver/base/base.go @@ -52,25 +52,29 @@ type Base struct { // Format errors received from the storage driver func (base *Base) setDriverName(e error) error { - if e != nil { - if actualErr, ok := e.(storagedriver.ErrUnsupportedMethod); ok { - actualErr.DriverName = base.StorageDriver.Name() - return actualErr - } - if actualErr, ok := e.(storagedriver.PathNotFoundError); ok { - actualErr.DriverName = base.StorageDriver.Name() - return actualErr - } - if actualErr, ok := e.(storagedriver.InvalidPathError); ok { - actualErr.DriverName = base.StorageDriver.Name() - return actualErr - } - if actualErr, ok := e.(storagedriver.InvalidOffsetError); ok { - actualErr.DriverName = base.StorageDriver.Name() - return actualErr + switch actual := e.(type) { + case nil: + return nil + case storagedriver.ErrUnsupportedMethod: + actual.DriverName = base.StorageDriver.Name() + return actual + case storagedriver.PathNotFoundError: + actual.DriverName = base.StorageDriver.Name() + return actual + case storagedriver.InvalidPathError: + actual.DriverName = base.StorageDriver.Name() + return actual + case storagedriver.InvalidOffsetError: + actual.DriverName = base.StorageDriver.Name() + return actual + default: + storageError := storagedriver.Error{ + DriverName: base.StorageDriver.Name(), + Enclosed: e, } + + return storageError } - return e } // GetContent wraps GetContent of underlying storage driver. diff --git a/registry/storage/driver/filesystem/driver.go b/registry/storage/driver/filesystem/driver.go index 20ccfce7..7dece0b3 100644 --- a/registry/storage/driver/filesystem/driver.go +++ b/registry/storage/driver/filesystem/driver.go @@ -248,7 +248,7 @@ func (d *driver) Delete(ctx context.Context, subPath string) error { // URLFor returns a URL which may be used to retrieve the content stored at the given path. // May return an UnsupportedMethodErr in certain StorageDriver implementations. func (d *driver) URLFor(ctx context.Context, path string, options map[string]interface{}) (string, error) { - return "", new(storagedriver.ErrUnsupportedMethod) + return "", storagedriver.ErrUnsupportedMethod{} } // fullPath returns the absolute path of a key within the Driver's storage. diff --git a/registry/storage/driver/gcs/gcs.go b/registry/storage/driver/gcs/gcs.go index 8dc96675..4cef972c 100644 --- a/registry/storage/driver/gcs/gcs.go +++ b/registry/storage/driver/gcs/gcs.go @@ -575,7 +575,7 @@ func (d *driver) Delete(context ctx.Context, path string) error { // Returns ErrUnsupportedMethod if this driver has no privateKey func (d *driver) URLFor(context ctx.Context, path string, options map[string]interface{}) (string, error) { if d.privateKey == nil { - return "", storagedriver.ErrUnsupportedMethod + return "", storagedriver.ErrUnsupportedMethod{} } name := d.pathToKey(path) @@ -584,7 +584,7 @@ func (d *driver) URLFor(context ctx.Context, path string, options map[string]int if ok { methodString, ok = method.(string) if !ok || (methodString != "GET" && methodString != "HEAD") { - return "", storagedriver.ErrUnsupportedMethod + return "", storagedriver.ErrUnsupportedMethod{} } } diff --git a/registry/storage/driver/inmemory/driver.go b/registry/storage/driver/inmemory/driver.go index 2dad0ec8..b5735c0a 100644 --- a/registry/storage/driver/inmemory/driver.go +++ b/registry/storage/driver/inmemory/driver.go @@ -258,5 +258,5 @@ func (d *driver) Delete(ctx context.Context, path string) error { // URLFor returns a URL which may be used to retrieve the content stored at the given path. // May return an UnsupportedMethodErr in certain StorageDriver implementations. func (d *driver) URLFor(ctx context.Context, path string, options map[string]interface{}) (string, error) { - return "", new(storagedriver.ErrUnsupportedMethod) + return "", storagedriver.ErrUnsupportedMethod{} } diff --git a/registry/storage/driver/oss/oss.go b/registry/storage/driver/oss/oss.go index 99bca366..c16b9949 100644 --- a/registry/storage/driver/oss/oss.go +++ b/registry/storage/driver/oss/oss.go @@ -748,7 +748,7 @@ func (d *driver) URLFor(ctx context.Context, path string, options map[string]int if ok { methodString, ok = method.(string) if !ok || (methodString != "GET" && methodString != "HEAD") { - return "", new(storagedriver.ErrUnsupportedMethod) + return "", storagedriver.ErrUnsupportedMethod{} } } diff --git a/registry/storage/driver/rados/rados.go b/registry/storage/driver/rados/rados.go index fa73c8d2..29bc3247 100644 --- a/registry/storage/driver/rados/rados.go +++ b/registry/storage/driver/rados/rados.go @@ -496,7 +496,7 @@ func (d *driver) Delete(ctx context.Context, objectPath string) error { // URLFor returns a URL which may be used to retrieve the content stored at the given path. // May return an UnsupportedMethodErr in certain StorageDriver implementations. func (d *driver) URLFor(ctx context.Context, path string, options map[string]interface{}) (string, error) { - return "", new(storagedriver.ErrUnsupportedMethod) + return "", storagedriver.ErrUnsupportedMethod{} } // Generate a blob identifier diff --git a/registry/storage/driver/s3/s3.go b/registry/storage/driver/s3/s3.go index 0a9d80c0..7672fbdb 100644 --- a/registry/storage/driver/s3/s3.go +++ b/registry/storage/driver/s3/s3.go @@ -759,7 +759,7 @@ func (d *driver) URLFor(ctx context.Context, path string, options map[string]int if ok { methodString, ok = method.(string) if !ok || (methodString != "GET" && methodString != "HEAD") { - return "", new(storagedriver.ErrUnsupportedMethod) + return "", storagedriver.ErrUnsupportedMethod{} } } diff --git a/registry/storage/driver/storagedriver.go b/registry/storage/driver/storagedriver.go index 996381c6..cd1c883b 100644 --- a/registry/storage/driver/storagedriver.go +++ b/registry/storage/driver/storagedriver.go @@ -131,3 +131,14 @@ type InvalidOffsetError struct { func (err InvalidOffsetError) Error() string { return fmt.Sprintf("[%s] Invalid offset: %d for path: %s", err.DriverName, err.Offset, err.Path) } + +// Error is a catch-all error type which captures an error string and +// the driver type on which it occured. +type Error struct { + DriverName string + Enclosed error +} + +func (err Error) Error() string { + return fmt.Sprintf("[%s] %s", err.DriverName, err.Enclosed) +} diff --git a/registry/storage/driver/testsuites/testsuites.go b/registry/storage/driver/testsuites/testsuites.go index f8117285..f99df8d9 100644 --- a/registry/storage/driver/testsuites/testsuites.go +++ b/registry/storage/driver/testsuites/testsuites.go @@ -626,7 +626,7 @@ func (suite *DriverSuite) TestURLFor(c *check.C) { c.Assert(err, check.IsNil) url, err := suite.StorageDriver.URLFor(suite.ctx, filename, nil) - if _, ok := err.(*storagedriver.ErrUnsupportedMethod); ok { + if _, ok := err.(storagedriver.ErrUnsupportedMethod); ok { return } c.Assert(err, check.IsNil) @@ -640,7 +640,7 @@ func (suite *DriverSuite) TestURLFor(c *check.C) { c.Assert(read, check.DeepEquals, contents) url, err = suite.StorageDriver.URLFor(suite.ctx, filename, map[string]interface{}{"method": "HEAD"}) - if _, ok := err.(*storagedriver.ErrUnsupportedMethod); ok { + if _, ok := err.(storagedriver.ErrUnsupportedMethod); ok { return } c.Assert(err, check.IsNil)