mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Update docker/distribution dependency
Signed-off-by: Stephen J Day <stephen.day@docker.com>
This commit is contained in:
parent
2f566f747b
commit
bfd5202c17
6 changed files with 484 additions and 386 deletions
|
@ -32,7 +32,7 @@ clone git github.com/coreos/go-etcd v2.0.0
|
|||
clone git github.com/hashicorp/consul v0.5.2
|
||||
|
||||
# get distribution packages
|
||||
clone git github.com/docker/distribution b9eeb328080d367dbde850ec6e94f1e4ac2b5efe
|
||||
clone git github.com/docker/distribution 419bbc2da637d9b2a812be78ef8436df7caac70d
|
||||
|
||||
clone git github.com/docker/libcontainer v2.2.1
|
||||
# libcontainer deps (see src/github.com/docker/libcontainer/update-vendor.sh)
|
||||
|
|
229
vendor/src/github.com/docker/distribution/registry/api/errcode/errors.go
vendored
Normal file
229
vendor/src/github.com/docker/distribution/registry/api/errcode/errors.go
vendored
Normal file
|
@ -0,0 +1,229 @@
|
|||
package errcode
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ErrorCoder is the base interface for ErrorCode and Error allowing
|
||||
// users of each to just call ErrorCode to get the real ID of each
|
||||
type ErrorCoder interface {
|
||||
ErrorCode() ErrorCode
|
||||
}
|
||||
|
||||
// ErrorCode represents the error type. The errors are serialized via strings
|
||||
// and the integer format may change and should *never* be exported.
|
||||
type ErrorCode int
|
||||
|
||||
// ErrorCode just returns itself
|
||||
func (ec ErrorCode) ErrorCode() ErrorCode {
|
||||
return ec
|
||||
}
|
||||
|
||||
// Error returns the ID/Value
|
||||
func (ec ErrorCode) Error() string {
|
||||
return ec.Descriptor().Value
|
||||
}
|
||||
|
||||
// Descriptor returns the descriptor for the error code.
|
||||
func (ec ErrorCode) Descriptor() ErrorDescriptor {
|
||||
d, ok := errorCodeToDescriptors[ec]
|
||||
|
||||
if !ok {
|
||||
return ErrorCodeUnknown.Descriptor()
|
||||
}
|
||||
|
||||
return d
|
||||
}
|
||||
|
||||
// String returns the canonical identifier for this error code.
|
||||
func (ec ErrorCode) String() string {
|
||||
return ec.Descriptor().Value
|
||||
}
|
||||
|
||||
// Message returned the human-readable error message for this error code.
|
||||
func (ec ErrorCode) Message() string {
|
||||
return ec.Descriptor().Message
|
||||
}
|
||||
|
||||
// MarshalText encodes the receiver into UTF-8-encoded text and returns the
|
||||
// result.
|
||||
func (ec ErrorCode) MarshalText() (text []byte, err error) {
|
||||
return []byte(ec.String()), nil
|
||||
}
|
||||
|
||||
// UnmarshalText decodes the form generated by MarshalText.
|
||||
func (ec *ErrorCode) UnmarshalText(text []byte) error {
|
||||
desc, ok := idToDescriptors[string(text)]
|
||||
|
||||
if !ok {
|
||||
desc = ErrorCodeUnknown.Descriptor()
|
||||
}
|
||||
|
||||
*ec = desc.Code
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WithDetail creates a new Error struct based on the passed-in info and
|
||||
// set the Detail property appropriately
|
||||
func (ec ErrorCode) WithDetail(detail interface{}) Error {
|
||||
if err, ok := detail.(error); ok {
|
||||
detail = err.Error()
|
||||
}
|
||||
|
||||
return Error{
|
||||
Code: ec,
|
||||
Detail: detail,
|
||||
}
|
||||
}
|
||||
|
||||
// Error provides a wrapper around ErrorCode with extra Details provided.
|
||||
type Error struct {
|
||||
Code ErrorCode `json:"code"`
|
||||
Detail interface{} `json:"detail,omitempty"`
|
||||
}
|
||||
|
||||
// ErrorCode returns the ID/Value of this Error
|
||||
func (e Error) ErrorCode() ErrorCode {
|
||||
return e.Code
|
||||
}
|
||||
|
||||
// Error returns a human readable representation of the error.
|
||||
func (e Error) Error() string {
|
||||
return fmt.Sprintf("%s: %s",
|
||||
strings.ToLower(strings.Replace(e.Code.String(), "_", " ", -1)),
|
||||
e.Code.Message())
|
||||
}
|
||||
|
||||
// Message returned the human-readable error message for this Error
|
||||
func (e Error) Message() string {
|
||||
return e.Code.Message()
|
||||
}
|
||||
|
||||
// ErrorDescriptor provides relevant information about a given error code.
|
||||
type ErrorDescriptor struct {
|
||||
// Code is the error code that this descriptor describes.
|
||||
Code ErrorCode
|
||||
|
||||
// Value provides a unique, string key, often captilized with
|
||||
// underscores, to identify the error code. This value is used as the
|
||||
// keyed value when serializing api errors.
|
||||
Value string
|
||||
|
||||
// Message is a short, human readable decription of the error condition
|
||||
// included in API responses.
|
||||
Message string
|
||||
|
||||
// Description provides a complete account of the errors purpose, suitable
|
||||
// for use in documentation.
|
||||
Description string
|
||||
|
||||
// HTTPStatusCode provides the http status code that is associated with
|
||||
// this error condition.
|
||||
HTTPStatusCode int
|
||||
}
|
||||
|
||||
// ParseErrorCode returns the value by the string error code.
|
||||
// `ErrorCodeUnknown` will be returned if the error is not known.
|
||||
func ParseErrorCode(value string) ErrorCode {
|
||||
ed, ok := idToDescriptors[value]
|
||||
if ok {
|
||||
return ed.Code
|
||||
}
|
||||
|
||||
return ErrorCodeUnknown
|
||||
}
|
||||
|
||||
// Errors provides the envelope for multiple errors and a few sugar methods
|
||||
// for use within the application.
|
||||
type Errors []error
|
||||
|
||||
func (errs Errors) Error() string {
|
||||
switch len(errs) {
|
||||
case 0:
|
||||
return "<nil>"
|
||||
case 1:
|
||||
return errs[0].Error()
|
||||
default:
|
||||
msg := "errors:\n"
|
||||
for _, err := range errs {
|
||||
msg += err.Error() + "\n"
|
||||
}
|
||||
return msg
|
||||
}
|
||||
}
|
||||
|
||||
// Len returns the current number of errors.
|
||||
func (errs Errors) Len() int {
|
||||
return len(errs)
|
||||
}
|
||||
|
||||
// jsonError extends Error with 'Message' so that we can include the
|
||||
// error text, just in case the receiver of the JSON doesn't have this
|
||||
// particular ErrorCode registered
|
||||
type jsonError struct {
|
||||
Code ErrorCode `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Detail interface{} `json:"detail,omitempty"`
|
||||
}
|
||||
|
||||
// MarshalJSON converts slice of error, ErrorCode or Error into a
|
||||
// slice of Error - then serializes
|
||||
func (errs Errors) MarshalJSON() ([]byte, error) {
|
||||
var tmpErrs struct {
|
||||
Errors []jsonError `json:"errors,omitempty"`
|
||||
}
|
||||
|
||||
for _, daErr := range errs {
|
||||
var err Error
|
||||
|
||||
switch daErr.(type) {
|
||||
case ErrorCode:
|
||||
err = daErr.(ErrorCode).WithDetail(nil)
|
||||
case Error:
|
||||
err = daErr.(Error)
|
||||
default:
|
||||
err = ErrorCodeUnknown.WithDetail(daErr)
|
||||
|
||||
}
|
||||
|
||||
tmpErrs.Errors = append(tmpErrs.Errors, jsonError{
|
||||
Code: err.Code,
|
||||
Message: err.Message(),
|
||||
Detail: err.Detail,
|
||||
})
|
||||
}
|
||||
|
||||
return json.Marshal(tmpErrs)
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes []Error and then converts it into slice of
|
||||
// Error or ErrorCode
|
||||
func (errs *Errors) UnmarshalJSON(data []byte) error {
|
||||
var tmpErrs struct {
|
||||
Errors []jsonError
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &tmpErrs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var newErrs Errors
|
||||
for _, daErr := range tmpErrs.Errors {
|
||||
if daErr.Detail == nil {
|
||||
// Error's w/o details get converted to ErrorCode
|
||||
newErrs = append(newErrs, daErr.Code)
|
||||
} else {
|
||||
// Error's w/ details are untouched
|
||||
newErrs = append(newErrs, Error{
|
||||
Code: daErr.Code,
|
||||
Detail: daErr.Detail,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
*errs = newErrs
|
||||
return nil
|
||||
}
|
86
vendor/src/github.com/docker/distribution/registry/api/errcode/register.go
vendored
Normal file
86
vendor/src/github.com/docker/distribution/registry/api/errcode/register.go
vendored
Normal file
|
@ -0,0 +1,86 @@
|
|||
package errcode
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
errorCodeToDescriptors = map[ErrorCode]ErrorDescriptor{}
|
||||
idToDescriptors = map[string]ErrorDescriptor{}
|
||||
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
|
||||
API classification.`,
|
||||
HTTPStatusCode: http.StatusInternalServerError,
|
||||
})
|
||||
|
||||
var nextCode = 1000
|
||||
var registerLock sync.Mutex
|
||||
|
||||
// Register will make the passed-in error known to the environment and
|
||||
// return a new ErrorCode
|
||||
func Register(group string, descriptor ErrorDescriptor) ErrorCode {
|
||||
registerLock.Lock()
|
||||
defer registerLock.Unlock()
|
||||
|
||||
descriptor.Code = ErrorCode(nextCode)
|
||||
|
||||
if _, ok := idToDescriptors[descriptor.Value]; ok {
|
||||
panic(fmt.Sprintf("ErrorValue %q is already registered", descriptor.Value))
|
||||
}
|
||||
if _, ok := errorCodeToDescriptors[descriptor.Code]; ok {
|
||||
panic(fmt.Sprintf("ErrorCode %v is already registered", descriptor.Code))
|
||||
}
|
||||
|
||||
groupToDescriptors[group] = append(groupToDescriptors[group], descriptor)
|
||||
errorCodeToDescriptors[descriptor.Code] = descriptor
|
||||
idToDescriptors[descriptor.Value] = descriptor
|
||||
|
||||
nextCode++
|
||||
return descriptor.Code
|
||||
}
|
||||
|
||||
type byValue []ErrorDescriptor
|
||||
|
||||
func (a byValue) Len() int { return len(a) }
|
||||
func (a byValue) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a byValue) Less(i, j int) bool { return a[i].Value < a[j].Value }
|
||||
|
||||
// GetGroupNames returns the list of Error group names that are registered
|
||||
func GetGroupNames() []string {
|
||||
keys := []string{}
|
||||
|
||||
for k := range groupToDescriptors {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
||||
|
||||
// GetErrorCodeGroup returns the named group of error descriptors
|
||||
func GetErrorCodeGroup(name string) []ErrorDescriptor {
|
||||
desc := groupToDescriptors[name]
|
||||
sort.Sort(byValue(desc))
|
||||
return desc
|
||||
}
|
||||
|
||||
// GetErrorAllDescriptors returns a slice of all ErrorDescriptors that are
|
||||
// registered, irrespective of what group they're in
|
||||
func GetErrorAllDescriptors() []ErrorDescriptor {
|
||||
result := []ErrorDescriptor{}
|
||||
|
||||
for _, group := range GetGroupNames() {
|
||||
result = append(result, GetErrorCodeGroup(group)...)
|
||||
}
|
||||
sort.Sort(byValue(result))
|
||||
return result
|
||||
}
|
|
@ -5,6 +5,7 @@ import (
|
|||
"regexp"
|
||||
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/registry/api/errcode"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -16,12 +17,12 @@ var (
|
|||
Description: `Name of the target repository.`,
|
||||
}
|
||||
|
||||
tagParameterDescriptor = ParameterDescriptor{
|
||||
Name: "tag",
|
||||
referenceParameterDescriptor = ParameterDescriptor{
|
||||
Name: "reference",
|
||||
Type: "string",
|
||||
Format: TagNameRegexp.String(),
|
||||
Required: true,
|
||||
Description: `Tag of the target manifiest.`,
|
||||
Description: `Tag or digest of the target manifest.`,
|
||||
}
|
||||
|
||||
uuidParameterDescriptor = ParameterDescriptor{
|
||||
|
@ -98,7 +99,7 @@ var (
|
|||
Format: "<length>",
|
||||
},
|
||||
},
|
||||
ErrorCodes: []ErrorCode{
|
||||
ErrorCodes: []errcode.ErrorCode{
|
||||
ErrorCodeUnauthorized,
|
||||
},
|
||||
Body: BodyDescriptor{
|
||||
|
@ -119,7 +120,7 @@ var (
|
|||
Format: "<length>",
|
||||
},
|
||||
},
|
||||
ErrorCodes: []ErrorCode{
|
||||
ErrorCodes: []errcode.ErrorCode{
|
||||
ErrorCodeUnauthorized,
|
||||
},
|
||||
Body: BodyDescriptor{
|
||||
|
@ -171,13 +172,8 @@ const (
|
|||
var APIDescriptor = struct {
|
||||
// RouteDescriptors provides a list of the routes available in the API.
|
||||
RouteDescriptors []RouteDescriptor
|
||||
|
||||
// ErrorDescriptors provides a list of the error codes and their
|
||||
// associated documentation and metadata.
|
||||
ErrorDescriptors []ErrorDescriptor
|
||||
}{
|
||||
RouteDescriptors: routeDescriptors,
|
||||
ErrorDescriptors: errorDescriptors,
|
||||
}
|
||||
|
||||
// RouteDescriptor describes a route specified by name.
|
||||
|
@ -275,7 +271,7 @@ type ResponseDescriptor struct {
|
|||
|
||||
// ErrorCodes enumerates the error codes that may be returned along with
|
||||
// the response.
|
||||
ErrorCodes []ErrorCode
|
||||
ErrorCodes []errcode.ErrorCode
|
||||
|
||||
// Body describes the body of the response, if any.
|
||||
Body BodyDescriptor
|
||||
|
@ -317,30 +313,6 @@ type ParameterDescriptor struct {
|
|||
Examples []string
|
||||
}
|
||||
|
||||
// ErrorDescriptor provides relevant information about a given error code.
|
||||
type ErrorDescriptor struct {
|
||||
// Code is the error code that this descriptor describes.
|
||||
Code ErrorCode
|
||||
|
||||
// Value provides a unique, string key, often captilized with
|
||||
// underscores, to identify the error code. This value is used as the
|
||||
// keyed value when serializing api errors.
|
||||
Value string
|
||||
|
||||
// Message is a short, human readable decription of the error condition
|
||||
// included in API responses.
|
||||
Message string
|
||||
|
||||
// Description provides a complete account of the errors purpose, suitable
|
||||
// for use in documentation.
|
||||
Description string
|
||||
|
||||
// HTTPStatusCodes provides a list of status under which this error
|
||||
// condition may arise. If it is empty, the error condition may be seen
|
||||
// for any status code.
|
||||
HTTPStatusCodes []int
|
||||
}
|
||||
|
||||
var routeDescriptors = []RouteDescriptor{
|
||||
{
|
||||
Name: RouteNameBase,
|
||||
|
@ -374,7 +346,7 @@ var routeDescriptors = []RouteDescriptor{
|
|||
ContentType: "application/json; charset=utf-8",
|
||||
Format: errorsBody,
|
||||
},
|
||||
ErrorCodes: []ErrorCode{
|
||||
ErrorCodes: []errcode.ErrorCode{
|
||||
ErrorCodeUnauthorized,
|
||||
},
|
||||
},
|
||||
|
@ -438,7 +410,7 @@ var routeDescriptors = []RouteDescriptor{
|
|||
ContentType: "application/json; charset=utf-8",
|
||||
Format: errorsBody,
|
||||
},
|
||||
ErrorCodes: []ErrorCode{
|
||||
ErrorCodes: []errcode.ErrorCode{
|
||||
ErrorCodeNameUnknown,
|
||||
},
|
||||
},
|
||||
|
@ -449,7 +421,7 @@ var routeDescriptors = []RouteDescriptor{
|
|||
ContentType: "application/json; charset=utf-8",
|
||||
Format: errorsBody,
|
||||
},
|
||||
ErrorCodes: []ErrorCode{
|
||||
ErrorCodes: []errcode.ErrorCode{
|
||||
ErrorCodeUnauthorized,
|
||||
},
|
||||
},
|
||||
|
@ -476,7 +448,7 @@ var routeDescriptors = []RouteDescriptor{
|
|||
},
|
||||
PathParameters: []ParameterDescriptor{
|
||||
nameParameterDescriptor,
|
||||
tagParameterDescriptor,
|
||||
referenceParameterDescriptor,
|
||||
},
|
||||
Successes: []ResponseDescriptor{
|
||||
{
|
||||
|
@ -495,7 +467,7 @@ var routeDescriptors = []RouteDescriptor{
|
|||
{
|
||||
Description: "The name or reference was invalid.",
|
||||
StatusCode: http.StatusBadRequest,
|
||||
ErrorCodes: []ErrorCode{
|
||||
ErrorCodes: []errcode.ErrorCode{
|
||||
ErrorCodeNameInvalid,
|
||||
ErrorCodeTagInvalid,
|
||||
},
|
||||
|
@ -511,14 +483,14 @@ var routeDescriptors = []RouteDescriptor{
|
|||
ContentType: "application/json; charset=utf-8",
|
||||
Format: errorsBody,
|
||||
},
|
||||
ErrorCodes: []ErrorCode{
|
||||
ErrorCodes: []errcode.ErrorCode{
|
||||
ErrorCodeUnauthorized,
|
||||
},
|
||||
},
|
||||
{
|
||||
Description: "The named manifest is not known to the registry.",
|
||||
StatusCode: http.StatusNotFound,
|
||||
ErrorCodes: []ErrorCode{
|
||||
ErrorCodes: []errcode.ErrorCode{
|
||||
ErrorCodeNameUnknown,
|
||||
ErrorCodeManifestUnknown,
|
||||
},
|
||||
|
@ -542,7 +514,7 @@ var routeDescriptors = []RouteDescriptor{
|
|||
},
|
||||
PathParameters: []ParameterDescriptor{
|
||||
nameParameterDescriptor,
|
||||
tagParameterDescriptor,
|
||||
referenceParameterDescriptor,
|
||||
},
|
||||
Body: BodyDescriptor{
|
||||
ContentType: "application/json; charset=utf-8",
|
||||
|
@ -573,7 +545,7 @@ var routeDescriptors = []RouteDescriptor{
|
|||
ContentType: "application/json; charset=utf-8",
|
||||
Format: errorsBody,
|
||||
},
|
||||
ErrorCodes: []ErrorCode{
|
||||
ErrorCodes: []errcode.ErrorCode{
|
||||
ErrorCodeNameInvalid,
|
||||
ErrorCodeTagInvalid,
|
||||
ErrorCodeManifestInvalid,
|
||||
|
@ -588,7 +560,7 @@ var routeDescriptors = []RouteDescriptor{
|
|||
ContentType: "application/json; charset=utf-8",
|
||||
Format: errorsBody,
|
||||
},
|
||||
ErrorCodes: []ErrorCode{
|
||||
ErrorCodes: []errcode.ErrorCode{
|
||||
ErrorCodeUnauthorized,
|
||||
},
|
||||
},
|
||||
|
@ -596,7 +568,7 @@ var routeDescriptors = []RouteDescriptor{
|
|||
Name: "Missing Layer(s)",
|
||||
Description: "One or more layers may be missing during a manifest upload. If so, the missing layers will be enumerated in the error response.",
|
||||
StatusCode: http.StatusBadRequest,
|
||||
ErrorCodes: []ErrorCode{
|
||||
ErrorCodes: []errcode.ErrorCode{
|
||||
ErrorCodeBlobUnknown,
|
||||
},
|
||||
Body: BodyDescriptor{
|
||||
|
@ -625,7 +597,7 @@ var routeDescriptors = []RouteDescriptor{
|
|||
Format: "<length>",
|
||||
},
|
||||
},
|
||||
ErrorCodes: []ErrorCode{
|
||||
ErrorCodes: []errcode.ErrorCode{
|
||||
ErrorCodeUnauthorized,
|
||||
},
|
||||
Body: BodyDescriptor{
|
||||
|
@ -639,7 +611,7 @@ var routeDescriptors = []RouteDescriptor{
|
|||
},
|
||||
{
|
||||
Method: "DELETE",
|
||||
Description: "Delete the manifest identified by `name` and `reference` where `reference` can be a tag or digest.",
|
||||
Description: "Delete the manifest identified by `name` and `reference`. Note that a manifest can _only_ be deleted by `digest`.",
|
||||
Requests: []RequestDescriptor{
|
||||
{
|
||||
Headers: []ParameterDescriptor{
|
||||
|
@ -648,7 +620,7 @@ var routeDescriptors = []RouteDescriptor{
|
|||
},
|
||||
PathParameters: []ParameterDescriptor{
|
||||
nameParameterDescriptor,
|
||||
tagParameterDescriptor,
|
||||
referenceParameterDescriptor,
|
||||
},
|
||||
Successes: []ResponseDescriptor{
|
||||
{
|
||||
|
@ -657,10 +629,10 @@ var routeDescriptors = []RouteDescriptor{
|
|||
},
|
||||
Failures: []ResponseDescriptor{
|
||||
{
|
||||
Name: "Invalid Name or Tag",
|
||||
Description: "The specified `name` or `tag` were invalid and the delete was unable to proceed.",
|
||||
Name: "Invalid Name or Reference",
|
||||
Description: "The specified `name` or `reference` were invalid and the delete was unable to proceed.",
|
||||
StatusCode: http.StatusBadRequest,
|
||||
ErrorCodes: []ErrorCode{
|
||||
ErrorCodes: []errcode.ErrorCode{
|
||||
ErrorCodeNameInvalid,
|
||||
ErrorCodeTagInvalid,
|
||||
},
|
||||
|
@ -680,7 +652,7 @@ var routeDescriptors = []RouteDescriptor{
|
|||
Format: "<length>",
|
||||
},
|
||||
},
|
||||
ErrorCodes: []ErrorCode{
|
||||
ErrorCodes: []errcode.ErrorCode{
|
||||
ErrorCodeUnauthorized,
|
||||
},
|
||||
Body: BodyDescriptor{
|
||||
|
@ -690,9 +662,9 @@ var routeDescriptors = []RouteDescriptor{
|
|||
},
|
||||
{
|
||||
Name: "Unknown Manifest",
|
||||
Description: "The specified `name` or `tag` are unknown to the registry and the delete was unable to proceed. Clients can assume the manifest was already deleted if this response is returned.",
|
||||
Description: "The specified `name` or `reference` are unknown to the registry and the delete was unable to proceed. Clients can assume the manifest was already deleted if this response is returned.",
|
||||
StatusCode: http.StatusNotFound,
|
||||
ErrorCodes: []ErrorCode{
|
||||
ErrorCodes: []errcode.ErrorCode{
|
||||
ErrorCodeNameUnknown,
|
||||
ErrorCodeManifestUnknown,
|
||||
},
|
||||
|
@ -765,7 +737,7 @@ var routeDescriptors = []RouteDescriptor{
|
|||
{
|
||||
Description: "There was a problem with the request that needs to be addressed by the client, such as an invalid `name` or `tag`.",
|
||||
StatusCode: http.StatusBadRequest,
|
||||
ErrorCodes: []ErrorCode{
|
||||
ErrorCodes: []errcode.ErrorCode{
|
||||
ErrorCodeNameInvalid,
|
||||
ErrorCodeDigestInvalid,
|
||||
},
|
||||
|
@ -782,7 +754,7 @@ var routeDescriptors = []RouteDescriptor{
|
|||
ContentType: "application/json; charset=utf-8",
|
||||
Format: errorsBody,
|
||||
},
|
||||
ErrorCodes: []ErrorCode{
|
||||
ErrorCodes: []errcode.ErrorCode{
|
||||
ErrorCodeNameUnknown,
|
||||
ErrorCodeBlobUnknown,
|
||||
},
|
||||
|
@ -834,7 +806,7 @@ var routeDescriptors = []RouteDescriptor{
|
|||
{
|
||||
Description: "There was a problem with the request that needs to be addressed by the client, such as an invalid `name` or `tag`.",
|
||||
StatusCode: http.StatusBadRequest,
|
||||
ErrorCodes: []ErrorCode{
|
||||
ErrorCodes: []errcode.ErrorCode{
|
||||
ErrorCodeNameInvalid,
|
||||
ErrorCodeDigestInvalid,
|
||||
},
|
||||
|
@ -846,7 +818,7 @@ var routeDescriptors = []RouteDescriptor{
|
|||
unauthorizedResponse,
|
||||
{
|
||||
StatusCode: http.StatusNotFound,
|
||||
ErrorCodes: []ErrorCode{
|
||||
ErrorCodes: []errcode.ErrorCode{
|
||||
ErrorCodeNameUnknown,
|
||||
ErrorCodeBlobUnknown,
|
||||
},
|
||||
|
@ -926,7 +898,7 @@ var routeDescriptors = []RouteDescriptor{
|
|||
{
|
||||
Name: "Invalid Name or Digest",
|
||||
StatusCode: http.StatusBadRequest,
|
||||
ErrorCodes: []ErrorCode{
|
||||
ErrorCodes: []errcode.ErrorCode{
|
||||
ErrorCodeDigestInvalid,
|
||||
ErrorCodeNameInvalid,
|
||||
},
|
||||
|
@ -970,7 +942,7 @@ var routeDescriptors = []RouteDescriptor{
|
|||
{
|
||||
Name: "Invalid Name or Digest",
|
||||
StatusCode: http.StatusBadRequest,
|
||||
ErrorCodes: []ErrorCode{
|
||||
ErrorCodes: []errcode.ErrorCode{
|
||||
ErrorCodeDigestInvalid,
|
||||
ErrorCodeNameInvalid,
|
||||
},
|
||||
|
@ -1024,7 +996,7 @@ var routeDescriptors = []RouteDescriptor{
|
|||
{
|
||||
Description: "There was an error processing the upload and it must be restarted.",
|
||||
StatusCode: http.StatusBadRequest,
|
||||
ErrorCodes: []ErrorCode{
|
||||
ErrorCodes: []errcode.ErrorCode{
|
||||
ErrorCodeDigestInvalid,
|
||||
ErrorCodeNameInvalid,
|
||||
ErrorCodeBlobUploadInvalid,
|
||||
|
@ -1038,7 +1010,7 @@ var routeDescriptors = []RouteDescriptor{
|
|||
{
|
||||
Description: "The upload is unknown to the registry. The upload must be restarted.",
|
||||
StatusCode: http.StatusNotFound,
|
||||
ErrorCodes: []ErrorCode{
|
||||
ErrorCodes: []errcode.ErrorCode{
|
||||
ErrorCodeBlobUploadUnknown,
|
||||
},
|
||||
Body: BodyDescriptor{
|
||||
|
@ -1096,7 +1068,7 @@ var routeDescriptors = []RouteDescriptor{
|
|||
{
|
||||
Description: "There was an error processing the upload and it must be restarted.",
|
||||
StatusCode: http.StatusBadRequest,
|
||||
ErrorCodes: []ErrorCode{
|
||||
ErrorCodes: []errcode.ErrorCode{
|
||||
ErrorCodeDigestInvalid,
|
||||
ErrorCodeNameInvalid,
|
||||
ErrorCodeBlobUploadInvalid,
|
||||
|
@ -1110,7 +1082,7 @@ var routeDescriptors = []RouteDescriptor{
|
|||
{
|
||||
Description: "The upload is unknown to the registry. The upload must be restarted.",
|
||||
StatusCode: http.StatusNotFound,
|
||||
ErrorCodes: []ErrorCode{
|
||||
ErrorCodes: []errcode.ErrorCode{
|
||||
ErrorCodeBlobUploadUnknown,
|
||||
},
|
||||
Body: BodyDescriptor{
|
||||
|
@ -1175,7 +1147,7 @@ var routeDescriptors = []RouteDescriptor{
|
|||
{
|
||||
Description: "There was an error processing the upload and it must be restarted.",
|
||||
StatusCode: http.StatusBadRequest,
|
||||
ErrorCodes: []ErrorCode{
|
||||
ErrorCodes: []errcode.ErrorCode{
|
||||
ErrorCodeDigestInvalid,
|
||||
ErrorCodeNameInvalid,
|
||||
ErrorCodeBlobUploadInvalid,
|
||||
|
@ -1189,7 +1161,7 @@ var routeDescriptors = []RouteDescriptor{
|
|||
{
|
||||
Description: "The upload is unknown to the registry. The upload must be restarted.",
|
||||
StatusCode: http.StatusNotFound,
|
||||
ErrorCodes: []ErrorCode{
|
||||
ErrorCodes: []errcode.ErrorCode{
|
||||
ErrorCodeBlobUploadUnknown,
|
||||
},
|
||||
Body: BodyDescriptor{
|
||||
|
@ -1266,7 +1238,7 @@ var routeDescriptors = []RouteDescriptor{
|
|||
{
|
||||
Description: "There was an error processing the upload and it must be restarted.",
|
||||
StatusCode: http.StatusBadRequest,
|
||||
ErrorCodes: []ErrorCode{
|
||||
ErrorCodes: []errcode.ErrorCode{
|
||||
ErrorCodeDigestInvalid,
|
||||
ErrorCodeNameInvalid,
|
||||
ErrorCodeBlobUploadInvalid,
|
||||
|
@ -1280,7 +1252,7 @@ var routeDescriptors = []RouteDescriptor{
|
|||
{
|
||||
Description: "The upload is unknown to the registry. The upload must be restarted.",
|
||||
StatusCode: http.StatusNotFound,
|
||||
ErrorCodes: []ErrorCode{
|
||||
ErrorCodes: []errcode.ErrorCode{
|
||||
ErrorCodeBlobUploadUnknown,
|
||||
},
|
||||
Body: BodyDescriptor{
|
||||
|
@ -1321,7 +1293,7 @@ var routeDescriptors = []RouteDescriptor{
|
|||
{
|
||||
Description: "An error was encountered processing the delete. The client may ignore this error.",
|
||||
StatusCode: http.StatusBadRequest,
|
||||
ErrorCodes: []ErrorCode{
|
||||
ErrorCodes: []errcode.ErrorCode{
|
||||
ErrorCodeNameInvalid,
|
||||
ErrorCodeBlobUploadInvalid,
|
||||
},
|
||||
|
@ -1334,7 +1306,7 @@ var routeDescriptors = []RouteDescriptor{
|
|||
{
|
||||
Description: "The upload is unknown to the registry. The client may ignore this error and assume the upload has been deleted.",
|
||||
StatusCode: http.StatusNotFound,
|
||||
ErrorCodes: []ErrorCode{
|
||||
ErrorCodes: []errcode.ErrorCode{
|
||||
ErrorCodeBlobUploadUnknown,
|
||||
},
|
||||
Body: BodyDescriptor{
|
||||
|
@ -1350,143 +1322,11 @@ var routeDescriptors = []RouteDescriptor{
|
|||
},
|
||||
}
|
||||
|
||||
// ErrorDescriptors provides a list of HTTP API Error codes that may be
|
||||
// encountered when interacting with the registry API.
|
||||
var errorDescriptors = []ErrorDescriptor{
|
||||
{
|
||||
Code: ErrorCodeUnknown,
|
||||
Value: "UNKNOWN",
|
||||
Message: "unknown error",
|
||||
Description: `Generic error returned when the error does not have an
|
||||
API classification.`,
|
||||
},
|
||||
{
|
||||
Code: ErrorCodeUnsupported,
|
||||
Value: "UNSUPPORTED",
|
||||
Message: "The operation is unsupported.",
|
||||
Description: `The operation was unsupported due to a missing
|
||||
implementation or invalid set of parameters.`,
|
||||
},
|
||||
{
|
||||
Code: ErrorCodeUnauthorized,
|
||||
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.`,
|
||||
},
|
||||
{
|
||||
Code: ErrorCodeDigestInvalid,
|
||||
Value: "DIGEST_INVALID",
|
||||
Message: "provided digest did not match uploaded content",
|
||||
Description: `When a blob is uploaded, the registry will check that
|
||||
the content matches the digest provided by the client. The error may
|
||||
include a detail structure with the key "digest", including the
|
||||
invalid digest string. This error may also be returned when a manifest
|
||||
includes an invalid layer digest.`,
|
||||
HTTPStatusCodes: []int{http.StatusBadRequest, http.StatusNotFound},
|
||||
},
|
||||
{
|
||||
Code: ErrorCodeSizeInvalid,
|
||||
Value: "SIZE_INVALID",
|
||||
Message: "provided length did not match content length",
|
||||
Description: `When a layer is uploaded, the provided size will be
|
||||
checked against the uploaded content. If they do not match, this error
|
||||
will be returned.`,
|
||||
HTTPStatusCodes: []int{http.StatusBadRequest},
|
||||
},
|
||||
{
|
||||
Code: ErrorCodeNameInvalid,
|
||||
Value: "NAME_INVALID",
|
||||
Message: "invalid repository name",
|
||||
Description: `Invalid repository name encountered either during
|
||||
manifest validation or any API operation.`,
|
||||
HTTPStatusCodes: []int{http.StatusBadRequest, http.StatusNotFound},
|
||||
},
|
||||
{
|
||||
Code: ErrorCodeTagInvalid,
|
||||
Value: "TAG_INVALID",
|
||||
Message: "manifest tag did not match URI",
|
||||
Description: `During a manifest upload, if the tag in the manifest
|
||||
does not match the uri tag, this error will be returned.`,
|
||||
HTTPStatusCodes: []int{http.StatusBadRequest, http.StatusNotFound},
|
||||
},
|
||||
{
|
||||
Code: ErrorCodeNameUnknown,
|
||||
Value: "NAME_UNKNOWN",
|
||||
Message: "repository name not known to registry",
|
||||
Description: `This is returned if the name used during an operation is
|
||||
unknown to the registry.`,
|
||||
HTTPStatusCodes: []int{http.StatusNotFound},
|
||||
},
|
||||
{
|
||||
Code: ErrorCodeManifestUnknown,
|
||||
Value: "MANIFEST_UNKNOWN",
|
||||
Message: "manifest unknown",
|
||||
Description: `This error is returned when the manifest, identified by
|
||||
name and tag is unknown to the repository.`,
|
||||
HTTPStatusCodes: []int{http.StatusNotFound},
|
||||
},
|
||||
{
|
||||
Code: ErrorCodeManifestInvalid,
|
||||
Value: "MANIFEST_INVALID",
|
||||
Message: "manifest invalid",
|
||||
Description: `During upload, manifests undergo several checks ensuring
|
||||
validity. If those checks fail, this error may be returned, unless a
|
||||
more specific error is included. The detail will contain information
|
||||
the failed validation.`,
|
||||
HTTPStatusCodes: []int{http.StatusBadRequest},
|
||||
},
|
||||
{
|
||||
Code: ErrorCodeManifestUnverified,
|
||||
Value: "MANIFEST_UNVERIFIED",
|
||||
Message: "manifest failed signature verification",
|
||||
Description: `During manifest upload, if the manifest fails signature
|
||||
verification, this error will be returned.`,
|
||||
HTTPStatusCodes: []int{http.StatusBadRequest},
|
||||
},
|
||||
{
|
||||
Code: ErrorCodeBlobUnknown,
|
||||
Value: "BLOB_UNKNOWN",
|
||||
Message: "blob unknown to registry",
|
||||
Description: `This error may be returned when a blob is unknown to the
|
||||
registry in a specified repository. This can be returned with a
|
||||
standard get or if a manifest references an unknown layer during
|
||||
upload.`,
|
||||
HTTPStatusCodes: []int{http.StatusBadRequest, http.StatusNotFound},
|
||||
},
|
||||
|
||||
{
|
||||
Code: ErrorCodeBlobUploadUnknown,
|
||||
Value: "BLOB_UPLOAD_UNKNOWN",
|
||||
Message: "blob upload unknown to registry",
|
||||
Description: `If a blob upload has been cancelled or was never
|
||||
started, this error code may be returned.`,
|
||||
HTTPStatusCodes: []int{http.StatusNotFound},
|
||||
},
|
||||
{
|
||||
Code: ErrorCodeBlobUploadInvalid,
|
||||
Value: "BLOB_UPLOAD_INVALID",
|
||||
Message: "blob upload invalid",
|
||||
Description: `The blob upload encountered an error and can no
|
||||
longer proceed.`,
|
||||
HTTPStatusCodes: []int{http.StatusNotFound},
|
||||
},
|
||||
}
|
||||
|
||||
var errorCodeToDescriptors map[ErrorCode]ErrorDescriptor
|
||||
var idToDescriptors map[string]ErrorDescriptor
|
||||
var routeDescriptorsMap map[string]RouteDescriptor
|
||||
|
||||
func init() {
|
||||
errorCodeToDescriptors = make(map[ErrorCode]ErrorDescriptor, len(errorDescriptors))
|
||||
idToDescriptors = make(map[string]ErrorDescriptor, len(errorDescriptors))
|
||||
routeDescriptorsMap = make(map[string]RouteDescriptor, len(routeDescriptors))
|
||||
|
||||
for _, descriptor := range errorDescriptors {
|
||||
errorCodeToDescriptors[descriptor.Code] = descriptor
|
||||
idToDescriptors[descriptor.Value] = descriptor
|
||||
}
|
||||
for _, descriptor := range routeDescriptors {
|
||||
routeDescriptorsMap[descriptor.Name] = descriptor
|
||||
}
|
||||
|
|
|
@ -1,194 +1,154 @@
|
|||
package v2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/distribution/registry/api/errcode"
|
||||
)
|
||||
|
||||
// ErrorCode represents the error type. The errors are serialized via strings
|
||||
// and the integer format may change and should *never* be exported.
|
||||
type ErrorCode int
|
||||
|
||||
const (
|
||||
// ErrorCodeUnknown is a catch-all for errors not defined below.
|
||||
ErrorCodeUnknown ErrorCode = iota
|
||||
const errGroup = "registry.api.v2"
|
||||
|
||||
var (
|
||||
// ErrorCodeUnsupported is returned when an operation is not supported.
|
||||
ErrorCodeUnsupported
|
||||
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
|
||||
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
|
||||
ErrorCodeDigestInvalid = errcode.Register(errGroup, errcode.ErrorDescriptor{
|
||||
Value: "DIGEST_INVALID",
|
||||
Message: "provided digest did not match uploaded content",
|
||||
Description: `When a blob is uploaded, the registry will check that
|
||||
the content matches the digest provided by the client. The error may
|
||||
include a detail structure with the key "digest", including the
|
||||
invalid digest string. This error may also be returned when a manifest
|
||||
includes an invalid layer digest.`,
|
||||
HTTPStatusCode: http.StatusBadRequest,
|
||||
})
|
||||
|
||||
// ErrorCodeSizeInvalid is returned when uploading a blob if the provided
|
||||
// size does not match the content length.
|
||||
ErrorCodeSizeInvalid
|
||||
ErrorCodeSizeInvalid = errcode.Register(errGroup, errcode.ErrorDescriptor{
|
||||
Value: "SIZE_INVALID",
|
||||
Message: "provided length did not match content length",
|
||||
Description: `When a layer is uploaded, the provided size will be
|
||||
checked against the uploaded content. If they do not match, this error
|
||||
will be returned.`,
|
||||
HTTPStatusCode: http.StatusBadRequest,
|
||||
})
|
||||
|
||||
// ErrorCodeNameInvalid is returned when the name in the manifest does not
|
||||
// match the provided name.
|
||||
ErrorCodeNameInvalid
|
||||
ErrorCodeNameInvalid = errcode.Register(errGroup, errcode.ErrorDescriptor{
|
||||
Value: "NAME_INVALID",
|
||||
Message: "invalid repository name",
|
||||
Description: `Invalid repository name encountered either during
|
||||
manifest validation or any API operation.`,
|
||||
HTTPStatusCode: http.StatusBadRequest,
|
||||
})
|
||||
|
||||
// ErrorCodeTagInvalid is returned when the tag in the manifest does not
|
||||
// match the provided tag.
|
||||
ErrorCodeTagInvalid
|
||||
ErrorCodeTagInvalid = errcode.Register(errGroup, errcode.ErrorDescriptor{
|
||||
Value: "TAG_INVALID",
|
||||
Message: "manifest tag did not match URI",
|
||||
Description: `During a manifest upload, if the tag in the manifest
|
||||
does not match the uri tag, this error will be returned.`,
|
||||
HTTPStatusCode: http.StatusBadRequest,
|
||||
})
|
||||
|
||||
// ErrorCodeNameUnknown when the repository name is not known.
|
||||
ErrorCodeNameUnknown
|
||||
ErrorCodeNameUnknown = errcode.Register(errGroup, errcode.ErrorDescriptor{
|
||||
Value: "NAME_UNKNOWN",
|
||||
Message: "repository name not known to registry",
|
||||
Description: `This is returned if the name used during an operation is
|
||||
unknown to the registry.`,
|
||||
HTTPStatusCode: http.StatusNotFound,
|
||||
})
|
||||
|
||||
// ErrorCodeManifestUnknown returned when image manifest is unknown.
|
||||
ErrorCodeManifestUnknown
|
||||
ErrorCodeManifestUnknown = errcode.Register(errGroup, errcode.ErrorDescriptor{
|
||||
Value: "MANIFEST_UNKNOWN",
|
||||
Message: "manifest unknown",
|
||||
Description: `This error is returned when the manifest, identified by
|
||||
name and tag is unknown to the repository.`,
|
||||
HTTPStatusCode: http.StatusNotFound,
|
||||
})
|
||||
|
||||
// ErrorCodeManifestInvalid returned when an image manifest is invalid,
|
||||
// typically during a PUT operation. This error encompasses all errors
|
||||
// encountered during manifest validation that aren't signature errors.
|
||||
ErrorCodeManifestInvalid
|
||||
ErrorCodeManifestInvalid = errcode.Register(errGroup, errcode.ErrorDescriptor{
|
||||
Value: "MANIFEST_INVALID",
|
||||
Message: "manifest invalid",
|
||||
Description: `During upload, manifests undergo several checks ensuring
|
||||
validity. If those checks fail, this error may be returned, unless a
|
||||
more specific error is included. The detail will contain information
|
||||
the failed validation.`,
|
||||
HTTPStatusCode: http.StatusBadRequest,
|
||||
})
|
||||
|
||||
// ErrorCodeManifestUnverified is returned when the manifest fails
|
||||
// signature verfication.
|
||||
ErrorCodeManifestUnverified
|
||||
ErrorCodeManifestUnverified = errcode.Register(errGroup, errcode.ErrorDescriptor{
|
||||
Value: "MANIFEST_UNVERIFIED",
|
||||
Message: "manifest failed signature verification",
|
||||
Description: `During manifest upload, if the manifest fails signature
|
||||
verification, this error will be returned.`,
|
||||
HTTPStatusCode: http.StatusBadRequest,
|
||||
})
|
||||
|
||||
// ErrorCodeManifestBlobUnknown is returned when a manifest blob is
|
||||
// unknown to the registry.
|
||||
ErrorCodeManifestBlobUnknown = errcode.Register(errGroup, errcode.ErrorDescriptor{
|
||||
Value: "MANIFEST_BLOB_UNKNOWN",
|
||||
Message: "blob unknown to registry",
|
||||
Description: `This error may be returned when a manifest blob is
|
||||
unknown to the registry.`,
|
||||
HTTPStatusCode: http.StatusBadRequest,
|
||||
})
|
||||
|
||||
// ErrorCodeBlobUnknown is returned when a blob is unknown to the
|
||||
// registry. This can happen when the manifest references a nonexistent
|
||||
// layer or the result is not found by a blob fetch.
|
||||
ErrorCodeBlobUnknown
|
||||
ErrorCodeBlobUnknown = errcode.Register(errGroup, errcode.ErrorDescriptor{
|
||||
Value: "BLOB_UNKNOWN",
|
||||
Message: "blob unknown to registry",
|
||||
Description: `This error may be returned when a blob is unknown to the
|
||||
registry in a specified repository. This can be returned with a
|
||||
standard get or if a manifest references an unknown layer during
|
||||
upload.`,
|
||||
HTTPStatusCode: http.StatusNotFound,
|
||||
})
|
||||
|
||||
// ErrorCodeBlobUploadUnknown is returned when an upload is unknown.
|
||||
ErrorCodeBlobUploadUnknown
|
||||
ErrorCodeBlobUploadUnknown = errcode.Register(errGroup, errcode.ErrorDescriptor{
|
||||
Value: "BLOB_UPLOAD_UNKNOWN",
|
||||
Message: "blob upload unknown to registry",
|
||||
Description: `If a blob upload has been cancelled or was never
|
||||
started, this error code may be returned.`,
|
||||
HTTPStatusCode: http.StatusNotFound,
|
||||
})
|
||||
|
||||
// ErrorCodeBlobUploadInvalid is returned when an upload is invalid.
|
||||
ErrorCodeBlobUploadInvalid
|
||||
)
|
||||
|
||||
// ParseErrorCode attempts to parse the error code string, returning
|
||||
// ErrorCodeUnknown if the error is not known.
|
||||
func ParseErrorCode(s string) ErrorCode {
|
||||
desc, ok := idToDescriptors[s]
|
||||
|
||||
if !ok {
|
||||
return ErrorCodeUnknown
|
||||
}
|
||||
|
||||
return desc.Code
|
||||
}
|
||||
|
||||
// Descriptor returns the descriptor for the error code.
|
||||
func (ec ErrorCode) Descriptor() ErrorDescriptor {
|
||||
d, ok := errorCodeToDescriptors[ec]
|
||||
|
||||
if !ok {
|
||||
return ErrorCodeUnknown.Descriptor()
|
||||
}
|
||||
|
||||
return d
|
||||
}
|
||||
|
||||
// String returns the canonical identifier for this error code.
|
||||
func (ec ErrorCode) String() string {
|
||||
return ec.Descriptor().Value
|
||||
}
|
||||
|
||||
// Message returned the human-readable error message for this error code.
|
||||
func (ec ErrorCode) Message() string {
|
||||
return ec.Descriptor().Message
|
||||
}
|
||||
|
||||
// MarshalText encodes the receiver into UTF-8-encoded text and returns the
|
||||
// result.
|
||||
func (ec ErrorCode) MarshalText() (text []byte, err error) {
|
||||
return []byte(ec.String()), nil
|
||||
}
|
||||
|
||||
// UnmarshalText decodes the form generated by MarshalText.
|
||||
func (ec *ErrorCode) UnmarshalText(text []byte) error {
|
||||
desc, ok := idToDescriptors[string(text)]
|
||||
|
||||
if !ok {
|
||||
desc = ErrorCodeUnknown.Descriptor()
|
||||
}
|
||||
|
||||
*ec = desc.Code
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Error provides a wrapper around ErrorCode with extra Details provided.
|
||||
type Error struct {
|
||||
Code ErrorCode `json:"code"`
|
||||
Message string `json:"message,omitempty"`
|
||||
Detail interface{} `json:"detail,omitempty"`
|
||||
}
|
||||
|
||||
// Error returns a human readable representation of the error.
|
||||
func (e Error) Error() string {
|
||||
return fmt.Sprintf("%s: %s",
|
||||
strings.ToLower(strings.Replace(e.Code.String(), "_", " ", -1)),
|
||||
e.Message)
|
||||
}
|
||||
|
||||
// Errors provides the envelope for multiple errors and a few sugar methods
|
||||
// for use within the application.
|
||||
type Errors struct {
|
||||
Errors []Error `json:"errors,omitempty"`
|
||||
}
|
||||
|
||||
// Push pushes an error on to the error stack, with the optional detail
|
||||
// argument. It is a programming error (ie panic) to push more than one
|
||||
// detail at a time.
|
||||
func (errs *Errors) Push(code ErrorCode, details ...interface{}) {
|
||||
if len(details) > 1 {
|
||||
panic("please specify zero or one detail items for this error")
|
||||
}
|
||||
|
||||
var detail interface{}
|
||||
if len(details) > 0 {
|
||||
detail = details[0]
|
||||
}
|
||||
|
||||
if err, ok := detail.(error); ok {
|
||||
detail = err.Error()
|
||||
}
|
||||
|
||||
errs.PushErr(Error{
|
||||
Code: code,
|
||||
Message: code.Message(),
|
||||
Detail: detail,
|
||||
ErrorCodeBlobUploadInvalid = errcode.Register(errGroup, errcode.ErrorDescriptor{
|
||||
Value: "BLOB_UPLOAD_INVALID",
|
||||
Message: "blob upload invalid",
|
||||
Description: `The blob upload encountered an error and can no
|
||||
longer proceed.`,
|
||||
HTTPStatusCode: http.StatusNotFound,
|
||||
})
|
||||
}
|
||||
|
||||
// PushErr pushes an error interface onto the error stack.
|
||||
func (errs *Errors) PushErr(err error) {
|
||||
switch err.(type) {
|
||||
case Error:
|
||||
errs.Errors = append(errs.Errors, err.(Error))
|
||||
default:
|
||||
errs.Errors = append(errs.Errors, Error{Message: err.Error()})
|
||||
}
|
||||
}
|
||||
|
||||
func (errs *Errors) Error() string {
|
||||
switch errs.Len() {
|
||||
case 0:
|
||||
return "<nil>"
|
||||
case 1:
|
||||
return errs.Errors[0].Error()
|
||||
default:
|
||||
msg := "errors:\n"
|
||||
for _, err := range errs.Errors {
|
||||
msg += err.Error() + "\n"
|
||||
}
|
||||
return msg
|
||||
}
|
||||
}
|
||||
|
||||
// Clear clears the errors.
|
||||
func (errs *Errors) Clear() {
|
||||
errs.Errors = errs.Errors[:0]
|
||||
}
|
||||
|
||||
// Len returns the current number of errors.
|
||||
func (errs *Errors) Len() int {
|
||||
return len(errs.Errors)
|
||||
}
|
||||
)
|
||||
|
|
|
@ -6,19 +6,10 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// TODO(stevvooe): Move these definitions back to an exported package. While
|
||||
// they are used with v2 definitions, their relevance expands beyond.
|
||||
// "distribution/names" is a candidate package.
|
||||
// TODO(stevvooe): Move these definitions to the future "reference" package.
|
||||
// While they are used with v2 definitions, their relevance expands beyond.
|
||||
|
||||
const (
|
||||
// RepositoryNameComponentMinLength is the minimum number of characters in a
|
||||
// single repository name slash-delimited component
|
||||
RepositoryNameComponentMinLength = 2
|
||||
|
||||
// RepositoryNameMinComponents is the minimum number of slash-delimited
|
||||
// components that a repository name must have
|
||||
RepositoryNameMinComponents = 1
|
||||
|
||||
// RepositoryNameTotalLengthMax is the maximum total number of characters in
|
||||
// a repository name
|
||||
RepositoryNameTotalLengthMax = 255
|
||||
|
@ -40,17 +31,13 @@ var RepositoryNameRegexp = regexp.MustCompile(`(?:` + RepositoryNameComponentReg
|
|||
// TagNameRegexp matches valid tag names. From docker/docker:graph/tags.go.
|
||||
var TagNameRegexp = regexp.MustCompile(`[\w][\w.-]{0,127}`)
|
||||
|
||||
// TODO(stevvooe): Contribute these exports back to core, so they are shared.
|
||||
// TagNameAnchoredRegexp matches valid tag names, anchored at the start and
|
||||
// end of the matched string.
|
||||
var TagNameAnchoredRegexp = regexp.MustCompile("^" + TagNameRegexp.String() + "$")
|
||||
|
||||
var (
|
||||
// ErrRepositoryNameComponentShort is returned when a repository name
|
||||
// contains a component which is shorter than
|
||||
// RepositoryNameComponentMinLength
|
||||
ErrRepositoryNameComponentShort = fmt.Errorf("repository name component must be %v or more characters", RepositoryNameComponentMinLength)
|
||||
|
||||
// ErrRepositoryNameMissingComponents is returned when a repository name
|
||||
// contains fewer than RepositoryNameMinComponents components
|
||||
ErrRepositoryNameMissingComponents = fmt.Errorf("repository name must have at least %v components", RepositoryNameMinComponents)
|
||||
// ErrRepositoryNameEmpty is returned for empty, invalid repository names.
|
||||
ErrRepositoryNameEmpty = fmt.Errorf("repository name must have at least one component")
|
||||
|
||||
// ErrRepositoryNameLong is returned when a repository name is longer than
|
||||
// RepositoryNameTotalLengthMax
|
||||
|
@ -76,21 +63,17 @@ var (
|
|||
// The result of the production, known as the "namespace", should be limited
|
||||
// to 255 characters.
|
||||
func ValidateRepositoryName(name string) error {
|
||||
if name == "" {
|
||||
return ErrRepositoryNameEmpty
|
||||
}
|
||||
|
||||
if len(name) > RepositoryNameTotalLengthMax {
|
||||
return ErrRepositoryNameLong
|
||||
}
|
||||
|
||||
components := strings.Split(name, "/")
|
||||
|
||||
if len(components) < RepositoryNameMinComponents {
|
||||
return ErrRepositoryNameMissingComponents
|
||||
}
|
||||
|
||||
for _, component := range components {
|
||||
if len(component) < RepositoryNameComponentMinLength {
|
||||
return ErrRepositoryNameComponentShort
|
||||
}
|
||||
|
||||
if !RepositoryNameComponentAnchoredRegexp.MatchString(component) {
|
||||
return ErrRepositoryNameComponentInvalid
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue