Move common error codes to errcode package

Several error codes are generally useful but tied to the v2 specification
definitions. This change moves these error code definitions into the common
package for use by the health package, which is not tied to the v2 API.

Signed-off-by: Stephen J Day <stephen.day@docker.com>
This commit is contained in:
Stephen J Day 2015-08-06 16:25:08 -07:00
parent 6ba799b69e
commit f141480d98
12 changed files with 65 additions and 52 deletions

View file

@ -50,7 +50,10 @@ func main() {
ErrorDescriptors []errcode.ErrorDescriptor ErrorDescriptors []errcode.ErrorDescriptor
}{ }{
RouteDescriptors: v2.APIDescriptor.RouteDescriptors, RouteDescriptors: v2.APIDescriptor.RouteDescriptors,
ErrorDescriptors: errcode.GetErrorCodeGroup("registry.api.v2"), ErrorDescriptors: append(errcode.GetErrorCodeGroup("registry.api.v2"),
// The following are part of the specification but provided by errcode default.
errcode.ErrorCodeUnauthorized.Descriptor(),
errcode.ErrorCodeUnsupported.Descriptor()),
} }
if err := tmpl.Execute(os.Stdout, data); err != nil { if err := tmpl.Execute(os.Stdout, data); err != nil {

View file

@ -2249,7 +2249,7 @@ The following headers will be returned with the response:
|Name|Description| |Name|Description|
|----|-----------| |----|-----------|
|`Content-Length`|Zero| |`Content-Length`|0|
|`Docker-Content-Digest`|Digest of the targeted content for the request.| |`Docker-Content-Digest`|Digest of the targeted content for the request.|

View file

@ -13,15 +13,45 @@ var (
groupToDescriptors = map[string][]ErrorDescriptor{} groupToDescriptors = map[string][]ErrorDescriptor{}
) )
// ErrorCodeUnknown is a generic error that can be used as a last var (
// resort if there is no situation-specific error message that can be used // ErrorCodeUnknown is a generic error that can be used as a last
var ErrorCodeUnknown = Register("errcode", ErrorDescriptor{ // resort if there is no situation-specific error message that can be used
ErrorCodeUnknown = Register("errcode", ErrorDescriptor{
Value: "UNKNOWN", Value: "UNKNOWN",
Message: "unknown error", Message: "unknown error",
Description: `Generic error returned when the error does not have an Description: `Generic error returned when the error does not have an
API classification.`, API classification.`,
HTTPStatusCode: http.StatusInternalServerError, HTTPStatusCode: http.StatusInternalServerError,
}) })
// ErrorCodeUnsupported is returned when an operation is not supported.
ErrorCodeUnsupported = Register("errcode", ErrorDescriptor{
Value: "UNSUPPORTED",
Message: "The operation is unsupported.",
Description: `The operation was unsupported due to a missing
implementation or invalid set of parameters.`,
HTTPStatusCode: http.StatusBadRequest,
})
// ErrorCodeUnauthorized is returned if a request is not authorized.
ErrorCodeUnauthorized = Register("errcode", ErrorDescriptor{
Value: "UNAUTHORIZED",
Message: "access to the requested resource is not authorized",
Description: `The access controller denied access for the operation on
a resource. Often this will be accompanied by a 401 Unauthorized
response status.`,
HTTPStatusCode: http.StatusUnauthorized,
})
// ErrorCodeUnavailable provides a common error to report unavialability
// of a service or endpoint.
ErrorCodeUnavailable = Register("errcode", ErrorDescriptor{
Value: "UNAVAILABLE",
Message: "service unavailable",
Description: "Returned when a service is not available",
HTTPStatusCode: http.StatusServiceUnavailable,
})
)
var nextCode = 1000 var nextCode = 1000
var registerLock sync.Mutex var registerLock sync.Mutex

View file

@ -124,7 +124,7 @@ var (
}, },
}, },
ErrorCodes: []errcode.ErrorCode{ ErrorCodes: []errcode.ErrorCode{
ErrorCodeUnauthorized, errcode.ErrorCodeUnauthorized,
}, },
Body: BodyDescriptor{ Body: BodyDescriptor{
ContentType: "application/json; charset=utf-8", ContentType: "application/json; charset=utf-8",
@ -145,7 +145,7 @@ var (
}, },
}, },
ErrorCodes: []errcode.ErrorCode{ ErrorCodes: []errcode.ErrorCode{
ErrorCodeUnauthorized, errcode.ErrorCodeUnauthorized,
}, },
Body: BodyDescriptor{ Body: BodyDescriptor{
ContentType: "application/json; charset=utf-8", ContentType: "application/json; charset=utf-8",
@ -374,7 +374,7 @@ var routeDescriptors = []RouteDescriptor{
Format: errorsBody, Format: errorsBody,
}, },
ErrorCodes: []errcode.ErrorCode{ ErrorCodes: []errcode.ErrorCode{
ErrorCodeUnauthorized, errcode.ErrorCodeUnauthorized,
}, },
}, },
{ {
@ -451,7 +451,7 @@ var routeDescriptors = []RouteDescriptor{
Format: errorsBody, Format: errorsBody,
}, },
ErrorCodes: []errcode.ErrorCode{ ErrorCodes: []errcode.ErrorCode{
ErrorCodeUnauthorized, errcode.ErrorCodeUnauthorized,
}, },
}, },
}, },
@ -506,7 +506,7 @@ var routeDescriptors = []RouteDescriptor{
Format: errorsBody, Format: errorsBody,
}, },
ErrorCodes: []errcode.ErrorCode{ ErrorCodes: []errcode.ErrorCode{
ErrorCodeUnauthorized, errcode.ErrorCodeUnauthorized,
}, },
}, },
}, },
@ -568,7 +568,7 @@ var routeDescriptors = []RouteDescriptor{
Format: errorsBody, Format: errorsBody,
}, },
ErrorCodes: []errcode.ErrorCode{ ErrorCodes: []errcode.ErrorCode{
ErrorCodeUnauthorized, errcode.ErrorCodeUnauthorized,
}, },
}, },
{ {
@ -645,7 +645,7 @@ var routeDescriptors = []RouteDescriptor{
Format: errorsBody, Format: errorsBody,
}, },
ErrorCodes: []errcode.ErrorCode{ ErrorCodes: []errcode.ErrorCode{
ErrorCodeUnauthorized, errcode.ErrorCodeUnauthorized,
}, },
}, },
{ {
@ -682,7 +682,7 @@ var routeDescriptors = []RouteDescriptor{
}, },
}, },
ErrorCodes: []errcode.ErrorCode{ ErrorCodes: []errcode.ErrorCode{
ErrorCodeUnauthorized, errcode.ErrorCodeUnauthorized,
}, },
Body: BodyDescriptor{ Body: BodyDescriptor{
ContentType: "application/json; charset=utf-8", ContentType: "application/json; charset=utf-8",
@ -737,7 +737,7 @@ var routeDescriptors = []RouteDescriptor{
}, },
}, },
ErrorCodes: []errcode.ErrorCode{ ErrorCodes: []errcode.ErrorCode{
ErrorCodeUnauthorized, errcode.ErrorCodeUnauthorized,
}, },
Body: BodyDescriptor{ Body: BodyDescriptor{
ContentType: "application/json; charset=utf-8", ContentType: "application/json; charset=utf-8",
@ -974,7 +974,7 @@ var routeDescriptors = []RouteDescriptor{
Format: errorsBody, Format: errorsBody,
}, },
ErrorCodes: []errcode.ErrorCode{ ErrorCodes: []errcode.ErrorCode{
ErrorCodeUnsupported, errcode.ErrorCodeUnsupported,
}, },
}, },
}, },

View file

@ -9,24 +9,6 @@ import (
const errGroup = "registry.api.v2" const errGroup = "registry.api.v2"
var ( var (
// ErrorCodeUnsupported is returned when an operation is not supported.
ErrorCodeUnsupported = errcode.Register(errGroup, errcode.ErrorDescriptor{
Value: "UNSUPPORTED",
Message: "The operation is unsupported.",
Description: `The operation was unsupported due to a missing
implementation or invalid set of parameters.`,
})
// ErrorCodeUnauthorized is returned if a request is not authorized.
ErrorCodeUnauthorized = errcode.Register(errGroup, errcode.ErrorDescriptor{
Value: "UNAUTHORIZED",
Message: "access to the requested resource is not authorized",
Description: `The access controller denied access for the operation on
a resource. Often this will be accompanied by a 401 Unauthorized
response status.`,
HTTPStatusCode: http.StatusUnauthorized,
})
// ErrorCodeDigestInvalid is returned when uploading a blob if the // ErrorCodeDigestInvalid is returned when uploading a blob if the
// provided digest does not match the blob contents. // provided digest does not match the blob contents.
ErrorCodeDigestInvalid = errcode.Register(errGroup, errcode.ErrorDescriptor{ ErrorCodeDigestInvalid = errcode.Register(errGroup, errcode.ErrorDescriptor{

View file

@ -8,7 +8,6 @@ import (
"net/http" "net/http"
"github.com/docker/distribution/registry/api/errcode" "github.com/docker/distribution/registry/api/errcode"
"github.com/docker/distribution/registry/api/v2"
) )
// UnexpectedHTTPStatusError is returned when an unexpected HTTP status is // UnexpectedHTTPStatusError is returned when an unexpected HTTP status is
@ -52,7 +51,7 @@ func handleErrorResponse(resp *http.Response) error {
if resp.StatusCode == 401 { if resp.StatusCode == 401 {
err := parseHTTPErrorResponse(resp.Body) err := parseHTTPErrorResponse(resp.Body)
if uErr, ok := err.(*UnexpectedHTTPResponseError); ok { if uErr, ok := err.(*UnexpectedHTTPResponseError); ok {
return v2.ErrorCodeUnauthorized.WithDetail(uErr.Response) return errcode.ErrorCodeUnauthorized.WithDetail(uErr.Response)
} }
return err return err
} }

View file

@ -21,7 +21,6 @@ import (
"github.com/docker/distribution/digest" "github.com/docker/distribution/digest"
"github.com/docker/distribution/manifest" "github.com/docker/distribution/manifest"
"github.com/docker/distribution/registry/api/errcode" "github.com/docker/distribution/registry/api/errcode"
"github.com/docker/distribution/registry/api/v2"
"github.com/docker/distribution/testutil" "github.com/docker/distribution/testutil"
) )
@ -782,10 +781,10 @@ func TestManifestUnauthorized(t *testing.T) {
if !ok { if !ok {
t.Fatalf("Unexpected error type: %#v", err) t.Fatalf("Unexpected error type: %#v", err)
} }
if v2Err.Code != v2.ErrorCodeUnauthorized { if v2Err.Code != errcode.ErrorCodeUnauthorized {
t.Fatalf("Unexpected error code: %s", v2Err.Code.String()) t.Fatalf("Unexpected error code: %s", v2Err.Code.String())
} }
if expected := v2.ErrorCodeUnauthorized.Message(); v2Err.Message != expected { if expected := errcode.ErrorCodeUnauthorized.Message(); v2Err.Message != expected {
t.Fatalf("Unexpected message value: %q, expected %q", v2Err.Message, expected) t.Fatalf("Unexpected message value: %q, expected %q", v2Err.Message, expected)
} }
} }

View file

@ -575,7 +575,7 @@ func (app *App) authorized(w http.ResponseWriter, r *http.Request, context *Cont
// base route is accessed. This section prevents us from making // base route is accessed. This section prevents us from making
// that mistake elsewhere in the code, allowing any operation to // that mistake elsewhere in the code, allowing any operation to
// proceed. // proceed.
if err := errcode.ServeJSON(w, v2.ErrorCodeUnauthorized); err != nil { if err := errcode.ServeJSON(w, errcode.ErrorCodeUnauthorized); err != nil {
ctxu.GetLogger(context).Errorf("error serving error json: %v (from %v)", err, context.Errors) ctxu.GetLogger(context).Errorf("error serving error json: %v (from %v)", err, context.Errors)
} }
return fmt.Errorf("forbidden: no repository name") return fmt.Errorf("forbidden: no repository name")
@ -590,7 +590,7 @@ func (app *App) authorized(w http.ResponseWriter, r *http.Request, context *Cont
// Add the appropriate WWW-Auth header // Add the appropriate WWW-Auth header
err.SetHeaders(w) err.SetHeaders(w)
if err := errcode.ServeJSON(w, v2.ErrorCodeUnauthorized.WithDetail(accessRecords)); err != nil { if err := errcode.ServeJSON(w, errcode.ErrorCodeUnauthorized.WithDetail(accessRecords)); err != nil {
ctxu.GetLogger(context).Errorf("error serving error json: %v (from %v)", err, context.Errors) ctxu.GetLogger(context).Errorf("error serving error json: %v (from %v)", err, context.Errors)
} }
default: default:

View file

@ -205,8 +205,8 @@ func TestNewApp(t *testing.T) {
if !ok { if !ok {
t.Fatalf("not an ErrorCoder: %#v", errs[0]) t.Fatalf("not an ErrorCoder: %#v", errs[0])
} }
if err2.ErrorCode() != v2.ErrorCodeUnauthorized { if err2.ErrorCode() != errcode.ErrorCodeUnauthorized {
t.Fatalf("unexpected error code: %v != %v", err2.ErrorCode(), v2.ErrorCodeUnauthorized) t.Fatalf("unexpected error code: %v != %v", err2.ErrorCode(), errcode.ErrorCodeUnauthorized)
} }
} }

View file

@ -81,7 +81,7 @@ func (bh *blobHandler) DeleteBlob(w http.ResponseWriter, r *http.Request) {
bh.Errors = append(bh.Errors, v2.ErrorCodeBlobUnknown) bh.Errors = append(bh.Errors, v2.ErrorCodeBlobUnknown)
case distribution.ErrUnsupported: case distribution.ErrUnsupported:
w.WriteHeader(http.StatusMethodNotAllowed) w.WriteHeader(http.StatusMethodNotAllowed)
bh.Errors = append(bh.Errors, v2.ErrorCodeUnsupported) bh.Errors = append(bh.Errors, errcode.ErrorCodeUnsupported)
default: default:
bh.Errors = append(bh.Errors, errcode.ErrorCodeUnknown) bh.Errors = append(bh.Errors, errcode.ErrorCodeUnknown)
} }

View file

@ -213,7 +213,7 @@ func (imh *imageManifestHandler) DeleteImageManifest(w http.ResponseWriter, r *h
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
return return
case distribution.ErrUnsupported: case distribution.ErrUnsupported:
imh.Errors = append(imh.Errors, v2.ErrorCodeUnsupported) imh.Errors = append(imh.Errors, errcode.ErrorCodeUnsupported)
w.WriteHeader(http.StatusMethodNotAllowed) w.WriteHeader(http.StatusMethodNotAllowed)
default: default:
imh.Errors = append(imh.Errors, errcode.ErrorCodeUnknown) imh.Errors = append(imh.Errors, errcode.ErrorCodeUnknown)

View file

@ -7,7 +7,7 @@ import (
"github.com/docker/distribution/context" "github.com/docker/distribution/context"
"github.com/docker/distribution/digest" "github.com/docker/distribution/digest"
"github.com/docker/distribution/manifest" "github.com/docker/distribution/manifest"
"github.com/docker/distribution/registry/api/v2" "github.com/docker/distribution/registry/api/errcode"
"github.com/docker/distribution/registry/client" "github.com/docker/distribution/registry/client"
"github.com/docker/distribution/registry/proxy/scheduler" "github.com/docker/distribution/registry/proxy/scheduler"
) )
@ -147,9 +147,9 @@ func manifestDigest(sm *manifest.SignedManifest) (digest.Digest, error) {
} }
func (pms proxyManifestStore) Put(manifest *manifest.SignedManifest) error { func (pms proxyManifestStore) Put(manifest *manifest.SignedManifest) error {
return v2.ErrorCodeUnsupported return errcode.ErrorCodeUnsupported
} }
func (pms proxyManifestStore) Delete(dgst digest.Digest) error { func (pms proxyManifestStore) Delete(dgst digest.Digest) error {
return v2.ErrorCodeUnsupported return errcode.ErrorCodeUnsupported
} }