import six
import abc
import traceback
import json
import dockerreg.exceptions as ex
from dockerreg.util.applicable import ApplicableClass,ApplicableMethod
from dockerreg.util import getgoarch, getgoos
@six.add_metaclass(abc.ABCMeta)
[docs]class Model(object):
[docs] def __init__(self,api,name,id=None):
self._api = api
self._name = name
self._id = id
if name is None:
raise ex.IllegalArgumentError("modeled object must have a name")
@property
def api(self):
"""
The :py:class:`dockerreg.api.BaseApiClient` corresponding to this :py:class:`.Model`.
"""
return self._api
@property
def name(self):
"""
The name (a :py:class:`str`) corresponding to this object.
"""
#if not self._name:
# return self._id
return self._name
@property
def id(self):
"""
The identifier (a :py:class:`str`) corresponding to this object, if any.
"""
return self._id
@abc.abstractmethod
[docs] def refresh(self):
"""
Refreshes this object's content from the registry.
:raises dockerreg.exceptions.ObjectNotFoundError: if the object no longer exists at the registry.
"""
@abc.abstractmethod
def __eq__(self,other):
pass
def __ne__(self,other):
return not self.__eq__(other)
@abc.abstractmethod
def __hash__(self,other):
pass
def __repr__(self):
return "<%s %s>" % (self.__class__.__name__,self.name)
@six.add_metaclass(abc.ABCMeta)
@ApplicableClass()
[docs]class Registry(Model):
[docs] def __init__(self,api,name):
super(Registry,self).__init__(api,name,id=None)
self._namespaces = None
self._repositories = None
@property
def namespaces(self):
"""
A :py:class:`list` of namespaces in this registry.
"""
if self._namespaces is None:
self._namespaces = self.get_namespaces()
return self._namespaces
@property
def repositories(self):
"""
A :py:class:`dict` of repositories in this registry, keyed by `<namespace>/<repository>` strings, with values :py:class:`dockerreg.models.Repository`.
"""
if self._repositories is None:
self._repositories = self.get_repositories()
return self._repositories
@abc.abstractmethod
@ApplicableMethod()
[docs] def get_namespaces(self,regexp=None):
"""
Return a list of namespaces in this registry, possibly filtered by regexp string.
:param str regexp: a regexp to filter over
:returns: a :py:class:`list` of namespaces in this registry, possibly filtered by `regexp`.
:rtype: :py:class:`list`
"""
@abc.abstractmethod
@ApplicableMethod()
[docs] def get_repositories(self,regexp=None,namespace_regexp=None):
"""
Return a dict of namespaces-to-repository lists in this registry.
:param str regexp: a regexp to filter over
:param str namespace_regexp: a regexp to filter over namespaces
:returns: a :py:class:`dict` of namespaces, whose values are lists of repositories, in this registry, possibly filtered by `regexp`.
:rtype: :py:class:`dict`
"""
[docs] def refresh(self):
self.get_repositories()
self.get_namespaces()
[docs] def ping(self):
"""
:returns: :py:data:`True` if the registry is responding; :py:data:`False` if not.
:rtype: :py:class:`bool`
"""
try:
self.api.ping()
return True
except:
LOG.debug(traceback.format_exc())
return False
[docs] def authping(self):
"""
:returns: :py:data:`True` if the registry is responding and the user is authenticated and authorized to the `/` URL (i.e. version check); :py:data:`False` if not.
:rtype: :py:class:`bool`
"""
try:
self.api.authping()
return True
except:
LOG.debug(traceback.format_exc())
return False
@abc.abstractmethod
@ApplicableMethod()
@abc.abstractmethod
@ApplicableMethod()
@abc.abstractmethod
@ApplicableMethod()
@abc.abstractmethod
@ApplicableMethod()
[docs] def check_image(self,repository,tag,arch=getgoarch,oss=getgoos):
"""
Ensures that the image and its layers are all present in the named repository at the given tag.
:param str repository: the full name of the image, including the namespace and repository.
:param str tag: the tag indicating the version of the image.
:param str arch: a GOARCH architecture string (i.e. amd64); defaults to the platform this library is running on; see https://golang.org/doc/install/source#environment for valid values.
:param str oss: a GOOS operating system string (i.e. linux); defaults to the platform this library is running on; see https://golang.org/doc/install/source#environment for valid values.
:returns: 0 if all layers are present in repository; non-zero otherwise.
"""
@abc.abstractmethod
@ApplicableMethod()
[docs] def pull_image(self,repository,tag,arch=getgoarch,oss=getgoos,
filebasename=None):
"""
Pulls the image descriptor and all layers, returning an :py:class:`Image`representing the downloaded image. If the `filebasename` parameter is set, the raw data will be cached in files instead of in memory.
:param str repository: the full name of the image, including the namespace and repository.
:param str tag: the tag indicating the version of the image.
:param str arch: a GOARCH architecture string (i.e. amd64); defaults to the platform this library is running on; see https://golang.org/doc/install/source#environment for valid values.
:param str oss: a GOOS operating system string (i.e. linux); defaults to the platform this library is running on; see https://golang.org/doc/install/source#environment for valid values.
:param str filebasename: if set, the image manifest and layers will be cached in files named `filebasename`.manifest and `filebasename`.<layer_id>.
:returns: a :py:class:`Image`.
"""
@abc.abstractmethod
@ApplicableMethod()
[docs] def get_image_size(self,repository,tag,arch=getgoarch,oss=getgoos,
filebasename=None):
"""
Pulls the image descriptor and enough layer content to determine the total size of all layers in the image, returning an :type:`int` specifying the total layer size in bytes. If the `filebasename` parameter is set, the raw data will be cached in files instead of in memory.
:param str repository: the full name of the image, including the namespace and repository.
:param str tag: the tag indicating the version of the image.
:param str arch: a GOARCH architecture string (i.e. amd64); defaults to the platform this library is running on; see https://golang.org/doc/install/source#environment for valid values.
:param str oss: a GOOS operating system string (i.e. linux); defaults to the platform this library is running on; see https://golang.org/doc/install/source#environment for valid values.
:param str filebasename: if set, the image manifest (and any layers, if they are fully downloaded) will be cached in files named `filebasename`.manifest and `filebasename`.<layer_id>.
:returns: a :py:class:`Image`.
"""
@abc.abstractmethod
@ApplicableMethod()
[docs] def get_image_created(self,repository,tag,arch=getgoarch,oss=getgoos,
filebasename=None):
"""
Pulls the image descriptor to determine the creation time of the most recent layer (which is effectively the image creation time), returning an :type:`str` specifying created time. If the `filebasename` parameter is set, the raw data will be cached in files instead of in memory.
:param str repository: the full name of the image, including the namespace and repository.
:param str tag: the tag indicating the version of the image.
:param str arch: a GOARCH architecture string (i.e. amd64); defaults to the platform this library is running on; see https://golang.org/doc/install/source#environment for valid values.
:param str oss: a GOOS operating system string (i.e. linux); defaults to the platform this library is running on; see https://golang.org/doc/install/source#environment for valid values.
:param str filebasename: if set, the image manifest (and any layers, if they are fully downloaded) will be cached in files named `filebasename`.manifest and `filebasename`.<layer_id>.
:returns: an :type:`str` specifying created time.
"""
@abc.abstractmethod
@ApplicableMethod()
[docs] def push_image(self,repository,tag,filebasename):
"""
Pushes the image referenced by filebasename to the given repository and tag.
:param str repository: the full name of the image, including the namespace and repository.
:param str tag: the tag indicating the version of the image.
:param str filebasename: if set, the image manifest and layers will be read from the cached copy in files named `filebasename`.manifest and `filebasename`.<layer_id>.
"""
@abc.abstractmethod
@ApplicableMethod()
[docs] def tag_image(self,repository,tag,newtag,arch=getgoarch,oss=getgoos):
"""
Applies a new tag to an existing image referenced by its tag.
:param str repository: the full name of the image, including the namespace and repository.
:param str tag: the tag indicating the version of the image.
:param str newtag: the new tag to be added.
:param str arch: a GOARCH architecture string (i.e. amd64); defaults to the platform this library is running on; see https://golang.org/doc/install/source#environment for valid values.
:param str oss: a GOOS operating system string (i.e. linux); defaults to the platform this library is running on; see https://golang.org/doc/install/source#environment for valid values.
:returns: a :py:class:`Image`.
"""
@abc.abstractmethod
@ApplicableMethod()
[docs] def pull_and_push_image(self,repository,tag,arch=getgoarch,oss=getgoos,
filebasename=None,refresh=False,
dst_registry=None,dst_repository=None,dst_tag=None,
dst_username=None,dst_password=None,
dst_no_verify=None,dst_cert=None,dst_ca_bundle=None,
dst_skip_docker_config=False,dst_no_cache=False,
dst_cache_file=None):
"""
Pulls the repository:tag image from this registry, and pushes it to dst_registry/dst_repository:dst_tag. If all dst* parameters are None, an IllegalArgumentError will be raised. If any of the dst* parameters are unspecified, their values will be taken from the current values of the specified image. This allows you to simply re-tag an image; copy it to another repository; or copy it to another repository.
"""
@abc.abstractmethod
@ApplicableMethod(
kwargs=[dict(name='layers',action='store_true',default=False)])
[docs] def delete_image(self,repository,tag,layers=False,
arch=getgoarch,oss=getgoos):
"""
Deletes the image.
:param str repository: the full name of the image, including the namespace and repository.
:param str tag: the tag indicating the version of the image.
:param bool layers: True if we should delete layers; defaults to False.
:param str arch: a GOARCH architecture string (i.e. amd64); defaults to the platform this library is running on; see https://golang.org/doc/install/source#environment for valid values.
:param str oss: a GOOS operating system string (i.e. linux); defaults to the platform this library is running on; see https://golang.org/doc/install/source#environment for valid values.
:returns: `None`.
"""
@abc.abstractmethod
@ApplicableMethod()
[docs] def delete_tag(self,repository,tag,arch=getgoarch,oss=getgoos):
"""
Deletes a tag.
:param str repository: the full name of the image, including the namespace and repository.
:param str tag: the tag indicating the version of the image.
:param str arch: a GOARCH architecture string (i.e. amd64); defaults to the platform this library is running on; see https://golang.org/doc/install/source#environment for valid values.
:param str oss: a GOOS operating system string (i.e. linux); defaults to the platform this library is running on; see https://golang.org/doc/install/source#environment for valid values.
:returns: `None`.
"""
def __eq__(self,other):
if self.__class__ == other.__class__ \
and self.name == other.name and self.id == other.id:
return True
return False
def __hash__(self):
return hash((self.__class__,self.name,self.id))
def __repr__(self):
return "<%s %s>" % (self.__class__.__name__,self.name)
@six.add_metaclass(abc.ABCMeta)
[docs]class Repository(Model):
[docs] def __init__(self,api,repository,registry):
super(Repository,self).__init__(api,repository,id=None)
self.registry = registry
self._tags = None
@abc.abstractmethod
@abc.abstractmethod
[docs] def get_image(self,tag,arch=None,oss=None,filebasename=None):
"""
Returns an :py:class:`Image`representing the requested image. If the `filebasename` parameter is set, any downloaded raw data will be cached in files instead of in memory.
:param str tag: the tag indicating the version of the image.
:param str filebasename: if set, the image manifest and layers will be cached in files named `filebasename`.manifest and `filebasename`.<layer_id>.
:param str arch: either None or a GOARCH architecture string (i.e. amd64). Some Registry versions support multi-platform images; if there is a choice, and if you do not specify a value, it will default to the platform this library is running on; see https://golang.org/doc/install/source#environment for valid values.
:param str oss: a GOOS operating system string (i.e. linux). Some Registry versions support multi-platform images; if there is a choice, and if you do not specify a value, it will default to the platform this library is running on; see https://golang.org/doc/install/source#environment for valid values.
:returns: a :py:class:`Image`.
"""
def __eq__(self,other):
if self.__class__ == other.__class__ \
and self.registry == other.registry \
and self.name == other.name and self.id == other.id:
return True
return False
def __hash__(self):
return hash((self.__class__,self.registry,self.name,self.id))
def __repr__(self):
return "<%s %s:%s>" % (self.__class__.__name__,self.registry.name,
self.name)
@six.add_metaclass(abc.ABCMeta)
[docs]class Image(Model):
[docs] def __init__(self,api,tag,repository,id=None):
super(Image,self).__init__(api,tag,id=id)
self.repository = repository
self._deleted = False
@property
def tag(self):
return self.name
@property
def deleted(self):
return self._deleted
def __eq__(self,other):
if self.__class__ == other.__class__ \
and self.repository == other.repository \
and self.name == other.name and self.id == other.id:
return True
return False
@abc.abstractmethod
[docs] def size(self):
"""
:returns: the total size of the blobs/layers that make up the image.
:rtype: :type:`int`
"""
def __hash__(self):
return hash((self.__class__,self.repository,self.name,self.id))
def __repr__(self):
return "<%s %s/%s:%s %s>" % (
self.__class__.__name__,self.repository.registry.name,
self.repository.name,self.name,str(self.id))
@six.add_metaclass(abc.ABCMeta)
[docs]class Manifest(Model):
_media_types = []
[docs] def __init__(self,api,blob={},raw=b'{}',media_type=None,
repository=None,tag=None,id=None):
name = None
if repository and tag:
name = "%s:%s" % (repository,tag)
super(Manifest,self).__init__(api,name,id=id)
self._attrs = blob
self._raw = raw
self._media_type = media_type
self._repository = repository
self._tag = tag
self._version = None
def __eq__(self,other):
if self.__class__ != other.__class__:
return False
if self.repository != other.repository or self.tag != other.tag \
or self.id != other.id:
return False
if self.raw != other.raw:
return False
return True
def __hash__(self):
return hash(
(self.__class__.__name__,self.repository,self.tag,self.id,
self.raw,self._attrs))
@abc.abstractmethod
[docs] def verify(self):
"""
:returns: `True` if verified; `None` if there is nothing to verify; or throws an Exception if verification fails.
"""
[docs] def modify(self,**kwargs):
"""
Modify this manifest. This could mean, for instance, for a v2-1
manifest, to change the repository and/or tag. It is manifest
version-defined; but all Manifest subclasses should at least
support the repository and tag modification keys.
"""
return
@property
def raw(self):
if not self._raw:
self._raw = json.dumps(
self._attrs,indent=3,separators=(',\n',': '))
return self._raw
@property
def valid_media_types(self):
return self.__class__._media_types
@property
def version(self):
return self._version
@property
def media_type(self):
return self._media_type
@property
def repository(self):
return self._repository
@property
def tag(self):
return self._tag
def __repr__(self):
idstr = ""
if self.id:
idstr = " " + str(self.id)
return "<%s %s:%s%s>" % (
self.__class__.__name__,self.repository,self.tag,idstr)
@six.add_metaclass(abc.ABCMeta)
[docs]class SignableMixin(object):
@abc.abstractmethod
[docs] def sign(self):
"""
Updates the :py:class:`Manifest` in place (specifically, updates the `_raw` instance variable (the `raw` property) with a new, signed raw manifest string, based on the current manifest attributes.
"""