Coverage for dxf/__init__.py : 92%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
""" Module for accessing a Docker v2 Registry """
from urllib.parse import urlencode # pylint: disable=import-error,no-name-in-module,wrong-import-order
# pylint: disable=wildcard-import
else: _binary_type = bytes # pylint: disable=redefined-builtin long = int
""" Hash bytes using the same method the registry uses (currently SHA-256).
:param buf: Bytes to hash :type buf: binary str
:rtype: str :returns: Hex-encoded hash of file's content """
""" Hash a file using the same method the registry uses (currently SHA-256).
:param filename: Name of file to hash :type filename: str
:rtype: str :returns: Hex-encoded hash of file's content """
# pylint: disable=no-member
# define __iter__ so requests thinks we're a stream # (models.py, PreparedRequest.prepare_body) assert not "called" # define fileno, tell and mode so requests can find length # (utils.py, super_len) def mode(self):
# pylint: disable=too-few-public-methods
# pylint: disable=too-few-public-methods
# pylint: disable=too-many-instance-attributes """ Class for communicating with a Docker v2 registry. Contains only operations which aren't related to repositories.
Can act as a context manager. For each context entered, a new `requests.Session <http://docs.python-requests.org/en/latest/user/advanced/#session-objects>`_ is obtained. Connections to the same host are shared by the session. When the context exits, all the session's connections are closed.
If you don't use :class:`DXFBase` as a context manager, each request uses an ephemeral session. If you don't read all the data from an iterator returned by :meth:`DXF.pull_blob` then the underlying connection won't be closed until Python garbage collects the iterator. """ # pylint: disable=too-many-arguments """ :param host: Host name of registry. Can contain port numbers. e.g. ``registry-1.docker.io``, ``localhost:5000``. :type host: str
:param auth: Authentication function to be called whenever authentication to the registry is required. Receives the :class:`DXFBase` object and a HTTP response object. It should call :meth:`authenticate` with a username, password and ``response`` before it returns. :type auth: function(dxf_obj, response)
:param insecure: Use HTTP instead of HTTPS (which is the default) when connecting to the registry. :type insecure: bool
:param auth_host: Host to use for token authentication. If set, overrides host returned by then registry. :type auth_host: str
:param tlsverify: When set to False, do not verify TLS certificate. :type tlsverify: bool """ except ImportError: import urllib3
def token(self): """ str: Authentication token. This will be obtained automatically when you call :meth:`authenticate`. If you've obtained a token previously, you can also set it but be aware tokens expire quickly. """
def token(self, value): 'Authorization': 'Bearer ' + value }
# pylint: disable=no-member
username=None, password=None, actions=None, response=None, authorization=None): # pylint: disable=too-many-arguments """ Authenticate to the registry using a username and password, an authorization header or otherwise as the anonymous user.
:param username: User name to authenticate as. :type username: str
:param password: User's password. :type password: str
:param actions: If you know which types of operation you need to make on the registry, specify them here. Valid actions are ``pull``, ``push`` and ``*``. :type actions: list
:param response: When the ``auth`` function you passed to :class:`DXFBase`'s constructor is called, it is passed a HTTP response object. Pass it back to :meth:`authenticate` to have it automatically detect which actions are required. :type response: requests.Response
:param authorization: ``Authorization`` header value. :type authorization: str
:rtype: str :returns: Authentication token, if the registry supports bearer tokens. Otherwise ``None``, and HTTP Basic auth is used. """ # pylint: disable=no-member raise exceptions.DXFUnexpectedStatusCodeError(response.status_code, requests.codes.unauthorized) 'Authorization': 'Basic ' + base64.b64encode(_to_bytes_2and3(username + ':' + password)).decode('utf-8') } 'Authorization': authorization } else: else: 'service': info['service'], 'scope': scope }) else:
""" List all repositories in the registry.
:param batch_size: Number of repository names to ask the server for at a time. :type batch_size: int
:param iterate: Whether to return iterator over the names or a list of all the names. :type iterate: bool
:rtype: list or iterator of strings :returns: Repository names. """ '_catalog', 'repositories', params={'n': batch_size})
""" Class for operating on a Docker v2 repositories. """ # pylint: disable=too-many-arguments """ :param host: Host name of registry. Can contain port numbers. e.g. ``registry-1.docker.io``, ``localhost:5000``. :type host: str
:param repo: Name of the repository to access on the registry. Typically this is of the form ``username/reponame`` but for your own registries you don't actually have to stick to that. :type repo: str
:param auth: Authentication function to be called whenever authentication to the registry is required. Receives the :class:`DXF` object and a HTTP response object. It should call :meth:`DXFBase.authenticate` with a username, password and ``response`` before it returns. :type auth: function(dxf_obj, response)
:param insecure: Use HTTP instead of HTTPS (which is the default) when connecting to the registry. :type insecure: bool
:param auth_host: Host to use for token authentication. If set, overrides host returned by then registry. :type auth_host: str
:param tlsverify: When set to False do not verify TLS certificate :type tlsverify: bool """
filename=None, progress=None, data=None, digest=None, check_exists=True): # pylint: disable=too-many-arguments """ Upload a file to the registry and return its (SHA-256) hash.
The registry is content-addressable so the file's content (aka blob) can be retrieved later by passing the hash to :meth:`pull_blob`.
:param filename: File to upload. :type filename: str
:param data: Data to upload if ``filename`` isn't given. The data is uploaded in chunks and you must also pass ``digest``. :type data: Generator or iterator
:param digest: Hash of the data to be uploaded in ``data``, if specified. :type digest: str (hex-encoded SHA-256)
:param progress: Optional function to call as the upload progresses. The function will be called with the hash of the file's content (or ``digest``), the blob just read from the file (or chunk from ``data``) and if ``filename`` is specified the total size of the file. :type progress: function(dgst, chunk, size)
:param check_exists: Whether to check if a blob with the same hash already exists in the registry. If so, it won't be uploaded again. :type check_exists: bool
:rtype: str :returns: Hash of file's content. """ else: # pylint: disable=no-member raise else:
# pylint: disable=no-self-use """ Download a blob from the registry given the hash of its content.
:param digest: Hash of the blob's content. :type digest: str
:param size: Whether to return the size of the blob too. :type size: bool
:param chunk_size: Number of bytes to download at a time. Defaults to 8192. :type chunk_size: int
:rtype: iterator :returns: If ``size`` is falsey, a byte string iterator over the blob's content. If ``size`` is truthy, a tuple containing the iterator and the blob's size. """ # pylint: disable=too-few-public-methods
""" Return the size of a blob in the registry given the hash of its content.
:param digest: Hash of the blob's content. :type digest: str
:rtype: long :returns: Whether the blob exists. """
""" Delete a blob from the registry given the hash of its content.
:param digest: Hash of the blob's content. :type digest: str """
# For dtuf; highly unlikely anyone else will want this 'mediaType': 'application/octet-stream', 'size': self.blob_size(dgst), 'digest': 'sha256:' + dgst } for dgst in digests] 'schemaVersion': 2, 'mediaType': 'application/vnd.docker.distribution.manifest.v2+json', # V2 Schema 2 insists on a config dependency. We're just using the # registry as a blob store so to save us uploading extra blobs, # use the first layer. 'config': { 'mediaType': 'application/octet-stream', 'size': layers[0]['size'], 'digest': layers[0]['digest'] }, 'layers': layers }, sort_keys=True)
""" Give a name (alias) to a manifest.
:param alias: Alias name :type alias: str
:param manifest_json: A V2 Schema 2 manifest JSON string :type digests: list """ 'manifests/' + alias, data=manifest_json, headers={'Content-Type': _schema2_mimetype})
# pylint: disable=too-many-locals """ Give a name (alias) to a set of blobs. Each blob is specified by the hash of its content.
:param alias: Alias name :type alias: str
:param digests: List of blob hashes. :type digests: list of strings
:rtype: str :returns: The registry manifest used to define the alias. You almost definitely won't need this. """ # pylint: disable=no-member raise
'manifests/' + alias, headers={'Accept': _schema2_mimetype + ', ' + _schema1_mimetype})
""" Get the manifest for an alias
:param alias: Alias name. :type alias: str
:rtype: str :returns: The manifest as string(JSON) """
alias=None, manifest=None, verify=True, sizes=False): """ Get the blob hashes assigned to an alias.
:param alias: Alias name. You almost definitely will only need to pass this argument. :type alias: str
:param manifest: If you previously obtained a manifest, specify it here instead of ``alias``. You almost definitely won't need to do this. :type manifest: str
:param verify: (v1 schema only) Whether to verify the integrity of the alias definition in the registry itself. You almost definitely won't need to change this from the default (``True``). :type verify: bool
:param sizes: Whether to return sizes of the blobs along with their hashes :type sizes: bool
:rtype: list :returns: If ``sizes`` is falsey, a list of blob hashes (strings) which are assigned to the alias. If ``sizes`` is truthy, a list of (hash,size) tuples for each blob. """ else: else: raise exceptions.DXFUnexpectedDigestMethodError(method, 'sha256') raise exceptions.DXFDigestMismatchError(dgst, expected_dgst)
raise exceptions.DXFUnexpectedDigestMethodError(method, 'sha256')
'''get the Docker Content Digest ID
:param str alias: alias name :rtype: str ''' # https://docs.docker.com/registry/spec/api/#deleting-an-image # Note When deleting a manifest from a registry version 2.3 or later, # the following header must be used when HEAD or GET-ing the manifest # to obtain the correct digest to delete: # Accept: application/vnd.docker.distribution.manifest.v2+json 'head', 'manifests/{}'.format(alias), headers={'Accept': _schema2_mimetype}, ).headers.get('Docker-Content-Digest')
""" Delete an alias from the registry. The blobs it points to won't be deleted. Use :meth:`del_blob` for that.
.. Note:: On private registry, garbage collection might need to be run manually; see: https://docs.docker.com/registry/garbage-collection/
:param alias: Alias name. :type alias: str
:rtype: list :returns: A list of blob hashes (strings) which were assigned to the alias. """
""" List all aliases defined in the repository.
:param batch_size: Number of alias names to ask the server for at a time. :type batch_size: int
:param iterate: Whether to return iterator over the names or a list of all the names. :type iterate: bool
:rtype: list or iterator of strings :returns: Alias names. """ 'tags/list', 'tags', params={'n': batch_size})
# v1 schema support functions below
'schemaVersion': 1, 'name': self._repo, 'tag': alias, 'fsLayers': [{'blobSum': 'sha256:' + dgst} for dgst in digests], 'history': [{'v1Compatibility': '{}'} for dgst in digests] }, sort_keys=True)
raise exceptions.DXFUnexpectedKeyTypeError(expkey['kty'], 'EC') raise exceptions.DXFUnexpectedKeyTypeError(expkey['crv'], 'P-256')
# Docker expects 32 bytes for x and y 'formatLength': format_length, 'formatTail': _urlsafe_b64encode(format_tail) }, { 'jwk': jkey, 'alg': 'ES256' }) ', "signatures": [' + jwstoken.serialize() + ']' + \ format_tail
manifest, content_digest=None, verify=True): # pylint: disable=too-many-locals,too-many-branches
# Adapted from https://github.com/joyent/node-docker-registry-client
raise exceptions.DXFDisallowedSignatureAlgorithmError('none') raise exceptions.DXFSignatureChainNotImplementedError()
'alg': alg, 'signature': sig['signature'], 'protected64': protected64, 'key': _import_key(sig['header']['jwk']), 'format_length': format_length, 'format_tail': format_tail })
signatures[0]['format_tail'] else:
raise exceptions.DXFUnexpectedDigestMethodError(method, 'sha256') raise exceptions.DXFDigestMismatchError(dgst, expected_dgst)
'payload': payload64, 'protected': sig['protected64'], 'signature': sig['signature'] }), sig['key'], sig['alg'])
raise exceptions.DXFUnexpectedDigestMethodError(method, 'sha256') |