169 lines
6.3 KiB
Python
169 lines
6.3 KiB
Python
|
import bitmath
|
||
|
|
||
|
|
||
|
class V2RegistryException(Exception):
|
||
|
def __init__(self, error_code_str, message, detail, http_status_code=400, repository=None,
|
||
|
scopes=None, is_read_only=False):
|
||
|
super(V2RegistryException, self).__init__(message)
|
||
|
self.http_status_code = http_status_code
|
||
|
self.repository = repository
|
||
|
self.scopes = scopes
|
||
|
self.is_read_only = is_read_only
|
||
|
|
||
|
self._error_code_str = error_code_str
|
||
|
self._detail = detail
|
||
|
|
||
|
def as_dict(self):
|
||
|
error_dict = {
|
||
|
'code': self._error_code_str,
|
||
|
'message': str(self),
|
||
|
'detail': self._detail if self._detail is not None else {},
|
||
|
}
|
||
|
|
||
|
if self.is_read_only:
|
||
|
error_dict['is_readonly'] = True
|
||
|
|
||
|
return error_dict
|
||
|
|
||
|
|
||
|
class BlobUnknown(V2RegistryException):
|
||
|
def __init__(self, detail=None):
|
||
|
super(BlobUnknown, self).__init__('BLOB_UNKNOWN', 'blob unknown to registry', detail, 404)
|
||
|
|
||
|
|
||
|
class BlobUploadInvalid(V2RegistryException):
|
||
|
def __init__(self, detail=None):
|
||
|
super(BlobUploadInvalid, self).__init__('BLOB_UPLOAD_INVALID', 'blob upload invalid', detail)
|
||
|
|
||
|
|
||
|
class BlobUploadUnknown(V2RegistryException):
|
||
|
def __init__(self, detail=None):
|
||
|
super(BlobUploadUnknown, self).__init__('BLOB_UPLOAD_UNKNOWN',
|
||
|
'blob upload unknown to registry', detail, 404)
|
||
|
|
||
|
|
||
|
class DigestInvalid(V2RegistryException):
|
||
|
def __init__(self, detail=None):
|
||
|
super(DigestInvalid, self).__init__('DIGEST_INVALID',
|
||
|
'provided digest did not match uploaded content', detail)
|
||
|
|
||
|
|
||
|
class ManifestBlobUnknown(V2RegistryException):
|
||
|
def __init__(self, detail=None):
|
||
|
super(ManifestBlobUnknown, self).__init__('MANIFEST_BLOB_UNKNOWN',
|
||
|
'manifest blob unknown to registry', detail)
|
||
|
|
||
|
|
||
|
class ManifestInvalid(V2RegistryException):
|
||
|
def __init__(self, detail=None, http_status_code=400):
|
||
|
super(ManifestInvalid, self).__init__('MANIFEST_INVALID', 'manifest invalid', detail,
|
||
|
http_status_code)
|
||
|
|
||
|
|
||
|
class ManifestUnknown(V2RegistryException):
|
||
|
def __init__(self, detail=None):
|
||
|
super(ManifestUnknown, self).__init__('MANIFEST_UNKNOWN', 'manifest unknown', detail, 404)
|
||
|
|
||
|
|
||
|
class TagExpired(V2RegistryException):
|
||
|
def __init__(self, message=None, detail=None):
|
||
|
super(TagExpired, self).__init__('TAG_EXPIRED',
|
||
|
message or 'Tag has expired',
|
||
|
detail,
|
||
|
404)
|
||
|
|
||
|
|
||
|
class ManifestUnverified(V2RegistryException):
|
||
|
def __init__(self, detail=None):
|
||
|
super(ManifestUnverified, self).__init__('MANIFEST_UNVERIFIED',
|
||
|
'manifest failed signature verification', detail)
|
||
|
|
||
|
|
||
|
class NameInvalid(V2RegistryException):
|
||
|
def __init__(self, detail=None, message=None):
|
||
|
super(NameInvalid, self).__init__('NAME_INVALID', message or 'invalid repository name', detail)
|
||
|
|
||
|
|
||
|
class NameUnknown(V2RegistryException):
|
||
|
def __init__(self, detail=None):
|
||
|
super(NameUnknown, self).__init__('NAME_UNKNOWN', 'repository name not known to registry',
|
||
|
detail, 404)
|
||
|
|
||
|
|
||
|
class SizeInvalid(V2RegistryException):
|
||
|
def __init__(self, detail=None):
|
||
|
super(SizeInvalid, self).__init__('SIZE_INVALID',
|
||
|
'provided length did not match content length', detail)
|
||
|
|
||
|
|
||
|
class TagAlreadyExists(V2RegistryException):
|
||
|
def __init__(self, detail=None):
|
||
|
super(TagAlreadyExists, self).__init__('TAG_ALREADY_EXISTS', 'tag was already pushed', detail,
|
||
|
409)
|
||
|
|
||
|
|
||
|
class TagInvalid(V2RegistryException):
|
||
|
def __init__(self, detail=None):
|
||
|
super(TagInvalid, self).__init__('TAG_INVALID', 'manifest tag did not match URI', detail)
|
||
|
|
||
|
|
||
|
class LayerTooLarge(V2RegistryException):
|
||
|
def __init__(self, uploaded=None, max_allowed=None):
|
||
|
detail = {}
|
||
|
message = 'Uploaded blob is larger than allowed by this registry'
|
||
|
|
||
|
if uploaded is not None and max_allowed is not None:
|
||
|
detail = {
|
||
|
'reason': '%s is greater than maximum allowed size %s' % (uploaded, max_allowed),
|
||
|
'max_allowed': max_allowed,
|
||
|
'uploaded': uploaded,}
|
||
|
|
||
|
up_str = bitmath.Byte(uploaded).best_prefix().format("{value:.2f} {unit}")
|
||
|
max_str = bitmath.Byte(max_allowed).best_prefix().format("{value:.2f} {unit}")
|
||
|
message = 'Uploaded blob of %s is larger than %s allowed by this registry' % (up_str,
|
||
|
max_str)
|
||
|
|
||
|
|
||
|
class Unauthorized(V2RegistryException):
|
||
|
def __init__(self, detail=None, repository=None, scopes=None):
|
||
|
super(Unauthorized,
|
||
|
self).__init__('UNAUTHORIZED', 'access to the requested resource is not authorized',
|
||
|
detail, 401, repository=repository, scopes=scopes)
|
||
|
|
||
|
|
||
|
class Unsupported(V2RegistryException):
|
||
|
def __init__(self, detail=None, message=None):
|
||
|
super(Unsupported, self).__init__('UNSUPPORTED', message or 'The operation is unsupported.',
|
||
|
detail, 405)
|
||
|
|
||
|
|
||
|
class InvalidLogin(V2RegistryException):
|
||
|
def __init__(self, message=None):
|
||
|
super(InvalidLogin, self).__init__('UNAUTHORIZED', message or
|
||
|
'Specified credentials are invalid', {}, 401)
|
||
|
|
||
|
|
||
|
class InvalidRequest(V2RegistryException):
|
||
|
def __init__(self, message=None):
|
||
|
super(InvalidRequest, self).__init__('INVALID_REQUEST', message or 'Invalid request', {}, 400)
|
||
|
|
||
|
|
||
|
class NamespaceDisabled(V2RegistryException):
|
||
|
def __init__(self, message=None):
|
||
|
message = message or 'This namespace is disabled. Please contact your system administrator.'
|
||
|
super(NamespaceDisabled, self).__init__('DENIED', message, {}, 405)
|
||
|
|
||
|
|
||
|
class BlobDownloadGeoBlocked(V2RegistryException):
|
||
|
def __init__(self, detail=None):
|
||
|
message = ('The region from which you are pulling has been geo-ip blocked. ' +
|
||
|
'Please contact the namespace owner.')
|
||
|
super(BlobDownloadGeoBlocked, self).__init__('DENIED', message, detail, 403)
|
||
|
|
||
|
|
||
|
class ReadOnlyMode(V2RegistryException):
|
||
|
def __init__(self, detail=None):
|
||
|
message = ('System is currently read-only. Pulls will succeed but all write operations ' +
|
||
|
'are currently suspended.')
|
||
|
super(ReadOnlyMode, self).__init__('DENIED', message, detail, 405, is_read_only=True)
|