forked from TrueCloudLab/distribution
2fcad2a10f
This package, ported from next-generation docker regsitry, includes route and error definitions. These facilitate compliant V2 client implementation. The portions of the HTTP API that are included in this package are considered to be locked down and should only be changed through a careful change proposal. Descriptor definitions package layout may change without affecting API behavior until the exported Go API is ready to be locked down. When the new registry stabilizes and becomes the master branch, this package can be vendored from the registry. Signed-off-by: Stephen J Day <stephen.day@docker.com>
185 lines
4.7 KiB
Go
185 lines
4.7 KiB
Go
package v2
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// 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
|
|
|
|
// ErrorCodeDigestInvalid is returned when uploading a blob if the
|
|
// provided digest does not match the blob contents.
|
|
ErrorCodeDigestInvalid
|
|
|
|
// ErrorCodeSizeInvalid is returned when uploading a blob if the provided
|
|
// size does not match the content length.
|
|
ErrorCodeSizeInvalid
|
|
|
|
// ErrorCodeNameInvalid is returned when the name in the manifest does not
|
|
// match the provided name.
|
|
ErrorCodeNameInvalid
|
|
|
|
// ErrorCodeTagInvalid is returned when the tag in the manifest does not
|
|
// match the provided tag.
|
|
ErrorCodeTagInvalid
|
|
|
|
// ErrorCodeNameUnknown when the repository name is not known.
|
|
ErrorCodeNameUnknown
|
|
|
|
// ErrorCodeManifestUnknown returned when image manifest is unknown.
|
|
ErrorCodeManifestUnknown
|
|
|
|
// 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
|
|
|
|
// ErrorCodeManifestUnverified is returned when the manifest fails
|
|
// signature verfication.
|
|
ErrorCodeManifestUnverified
|
|
|
|
// 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
|
|
|
|
// ErrorCodeBlobUploadUnknown is returned when an upload is unknown.
|
|
ErrorCodeBlobUploadUnknown
|
|
)
|
|
|
|
// 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,
|
|
})
|
|
}
|
|
|
|
// 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)
|
|
}
|