diff --git a/cmd/registry-api-descriptor-template/main.go b/cmd/registry-api-descriptor-template/main.go index 05a1b487..61eab8ec 100644 --- a/cmd/registry-api-descriptor-template/main.go +++ b/cmd/registry-api-descriptor-template/main.go @@ -50,7 +50,10 @@ func main() { ErrorDescriptors []errcode.ErrorDescriptor }{ 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 { diff --git a/docs/spec/api.md b/docs/spec/api.md index 9b56b6c5..40e21e41 100644 --- a/docs/spec/api.md +++ b/docs/spec/api.md @@ -2249,7 +2249,7 @@ The following headers will be returned with the response: |Name|Description| |----|-----------| -|`Content-Length`|Zero| +|`Content-Length`|0| |`Docker-Content-Digest`|Digest of the targeted content for the request.| diff --git a/registry/api/errcode/register.go b/registry/api/errcode/register.go index 42f911b3..e1c93f38 100644 --- a/registry/api/errcode/register.go +++ b/registry/api/errcode/register.go @@ -13,15 +13,45 @@ var ( groupToDescriptors = map[string][]ErrorDescriptor{} ) -// ErrorCodeUnknown is a generic error that can be used as a last -// resort if there is no situation-specific error message that can be used -var ErrorCodeUnknown = Register("errcode", ErrorDescriptor{ - Value: "UNKNOWN", - Message: "unknown error", - Description: `Generic error returned when the error does not have an +var ( + // ErrorCodeUnknown is a generic error that can be used as a last + // resort if there is no situation-specific error message that can be used + ErrorCodeUnknown = Register("errcode", ErrorDescriptor{ + Value: "UNKNOWN", + Message: "unknown error", + Description: `Generic error returned when the error does not have an 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 registerLock sync.Mutex diff --git a/registry/api/v2/descriptors.go b/registry/api/v2/descriptors.go index 0ef64f88..09289b96 100644 --- a/registry/api/v2/descriptors.go +++ b/registry/api/v2/descriptors.go @@ -124,7 +124,7 @@ var ( }, }, ErrorCodes: []errcode.ErrorCode{ - ErrorCodeUnauthorized, + errcode.ErrorCodeUnauthorized, }, Body: BodyDescriptor{ ContentType: "application/json; charset=utf-8", @@ -145,7 +145,7 @@ var ( }, }, ErrorCodes: []errcode.ErrorCode{ - ErrorCodeUnauthorized, + errcode.ErrorCodeUnauthorized, }, Body: BodyDescriptor{ ContentType: "application/json; charset=utf-8", @@ -374,7 +374,7 @@ var routeDescriptors = []RouteDescriptor{ Format: errorsBody, }, ErrorCodes: []errcode.ErrorCode{ - ErrorCodeUnauthorized, + errcode.ErrorCodeUnauthorized, }, }, { @@ -451,7 +451,7 @@ var routeDescriptors = []RouteDescriptor{ Format: errorsBody, }, ErrorCodes: []errcode.ErrorCode{ - ErrorCodeUnauthorized, + errcode.ErrorCodeUnauthorized, }, }, }, @@ -506,7 +506,7 @@ var routeDescriptors = []RouteDescriptor{ Format: errorsBody, }, ErrorCodes: []errcode.ErrorCode{ - ErrorCodeUnauthorized, + errcode.ErrorCodeUnauthorized, }, }, }, @@ -568,7 +568,7 @@ var routeDescriptors = []RouteDescriptor{ Format: errorsBody, }, ErrorCodes: []errcode.ErrorCode{ - ErrorCodeUnauthorized, + errcode.ErrorCodeUnauthorized, }, }, { @@ -645,7 +645,7 @@ var routeDescriptors = []RouteDescriptor{ Format: errorsBody, }, ErrorCodes: []errcode.ErrorCode{ - ErrorCodeUnauthorized, + errcode.ErrorCodeUnauthorized, }, }, { @@ -682,7 +682,7 @@ var routeDescriptors = []RouteDescriptor{ }, }, ErrorCodes: []errcode.ErrorCode{ - ErrorCodeUnauthorized, + errcode.ErrorCodeUnauthorized, }, Body: BodyDescriptor{ ContentType: "application/json; charset=utf-8", @@ -737,7 +737,7 @@ var routeDescriptors = []RouteDescriptor{ }, }, ErrorCodes: []errcode.ErrorCode{ - ErrorCodeUnauthorized, + errcode.ErrorCodeUnauthorized, }, Body: BodyDescriptor{ ContentType: "application/json; charset=utf-8", @@ -974,7 +974,7 @@ var routeDescriptors = []RouteDescriptor{ Format: errorsBody, }, ErrorCodes: []errcode.ErrorCode{ - ErrorCodeUnsupported, + errcode.ErrorCodeUnsupported, }, }, }, diff --git a/registry/api/v2/errors.go b/registry/api/v2/errors.go index 87e27f2e..ece52a2c 100644 --- a/registry/api/v2/errors.go +++ b/registry/api/v2/errors.go @@ -9,24 +9,6 @@ import ( const errGroup = "registry.api.v2" 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 // provided digest does not match the blob contents. ErrorCodeDigestInvalid = errcode.Register(errGroup, errcode.ErrorDescriptor{ diff --git a/registry/client/errors.go b/registry/client/errors.go index ebd1c36c..7305c021 100644 --- a/registry/client/errors.go +++ b/registry/client/errors.go @@ -8,7 +8,6 @@ import ( "net/http" "github.com/docker/distribution/registry/api/errcode" - "github.com/docker/distribution/registry/api/v2" ) // UnexpectedHTTPStatusError is returned when an unexpected HTTP status is @@ -52,7 +51,7 @@ func handleErrorResponse(resp *http.Response) error { if resp.StatusCode == 401 { err := parseHTTPErrorResponse(resp.Body) if uErr, ok := err.(*UnexpectedHTTPResponseError); ok { - return v2.ErrorCodeUnauthorized.WithDetail(uErr.Response) + return errcode.ErrorCodeUnauthorized.WithDetail(uErr.Response) } return err } diff --git a/registry/client/repository_test.go b/registry/client/repository_test.go index 26201763..8a7a598e 100644 --- a/registry/client/repository_test.go +++ b/registry/client/repository_test.go @@ -21,7 +21,6 @@ import ( "github.com/docker/distribution/digest" "github.com/docker/distribution/manifest" "github.com/docker/distribution/registry/api/errcode" - "github.com/docker/distribution/registry/api/v2" "github.com/docker/distribution/testutil" ) @@ -782,10 +781,10 @@ func TestManifestUnauthorized(t *testing.T) { if !ok { 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()) } - 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) } } diff --git a/registry/handlers/app.go b/registry/handlers/app.go index ab33e8a6..11d91120 100644 --- a/registry/handlers/app.go +++ b/registry/handlers/app.go @@ -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 // that mistake elsewhere in the code, allowing any operation to // 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) } 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 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) } default: diff --git a/registry/handlers/app_test.go b/registry/handlers/app_test.go index 6f597527..3ef2342c 100644 --- a/registry/handlers/app_test.go +++ b/registry/handlers/app_test.go @@ -205,8 +205,8 @@ func TestNewApp(t *testing.T) { if !ok { t.Fatalf("not an ErrorCoder: %#v", errs[0]) } - if err2.ErrorCode() != v2.ErrorCodeUnauthorized { - t.Fatalf("unexpected error code: %v != %v", err2.ErrorCode(), v2.ErrorCodeUnauthorized) + if err2.ErrorCode() != errcode.ErrorCodeUnauthorized { + t.Fatalf("unexpected error code: %v != %v", err2.ErrorCode(), errcode.ErrorCodeUnauthorized) } } diff --git a/registry/handlers/blob.go b/registry/handlers/blob.go index b7c06ea2..fd514ec0 100644 --- a/registry/handlers/blob.go +++ b/registry/handlers/blob.go @@ -81,7 +81,7 @@ func (bh *blobHandler) DeleteBlob(w http.ResponseWriter, r *http.Request) { bh.Errors = append(bh.Errors, v2.ErrorCodeBlobUnknown) case distribution.ErrUnsupported: w.WriteHeader(http.StatusMethodNotAllowed) - bh.Errors = append(bh.Errors, v2.ErrorCodeUnsupported) + bh.Errors = append(bh.Errors, errcode.ErrorCodeUnsupported) default: bh.Errors = append(bh.Errors, errcode.ErrorCodeUnknown) } diff --git a/registry/handlers/images.go b/registry/handlers/images.go index dbe7b706..f5354399 100644 --- a/registry/handlers/images.go +++ b/registry/handlers/images.go @@ -213,7 +213,7 @@ func (imh *imageManifestHandler) DeleteImageManifest(w http.ResponseWriter, r *h w.WriteHeader(http.StatusNotFound) return case distribution.ErrUnsupported: - imh.Errors = append(imh.Errors, v2.ErrorCodeUnsupported) + imh.Errors = append(imh.Errors, errcode.ErrorCodeUnsupported) w.WriteHeader(http.StatusMethodNotAllowed) default: imh.Errors = append(imh.Errors, errcode.ErrorCodeUnknown) diff --git a/registry/proxy/proxymanifeststore.go b/registry/proxy/proxymanifeststore.go index 5b79c8ce..8921998a 100644 --- a/registry/proxy/proxymanifeststore.go +++ b/registry/proxy/proxymanifeststore.go @@ -7,7 +7,7 @@ import ( "github.com/docker/distribution/context" "github.com/docker/distribution/digest" "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/proxy/scheduler" ) @@ -147,9 +147,9 @@ func manifestDigest(sm *manifest.SignedManifest) (digest.Digest, error) { } func (pms proxyManifestStore) Put(manifest *manifest.SignedManifest) error { - return v2.ErrorCodeUnsupported + return errcode.ErrorCodeUnsupported } func (pms proxyManifestStore) Delete(dgst digest.Digest) error { - return v2.ErrorCodeUnsupported + return errcode.ErrorCodeUnsupported }