mirror of https://github.com/docker/docker-py.git
Add methods for /distribution/<name>/json endpoint
Signed-off-by: Joffrey F <joffrey@docker.com>
This commit is contained in:
parent
f39c0dc18d
commit
bedabbfa35
|
@ -245,6 +245,27 @@ class ImageApiMixin(object):
|
|||
self._get(self._url("/images/{0}/json", image)), True
|
||||
)
|
||||
|
||||
@utils.minimum_version('1.30')
|
||||
@utils.check_resource('image')
|
||||
def inspect_distribution(self, image):
|
||||
"""
|
||||
Get image digest and platform information by contacting the registry.
|
||||
|
||||
Args:
|
||||
image (str): The image name to inspect
|
||||
|
||||
Returns:
|
||||
(dict): A dict containing distribution data
|
||||
|
||||
Raises:
|
||||
:py:class:`docker.errors.APIError`
|
||||
If the server returns an error.
|
||||
"""
|
||||
|
||||
return self._result(
|
||||
self._get(self._url("/distribution/{0}/json", image)), True
|
||||
)
|
||||
|
||||
def load_image(self, data, quiet=None):
|
||||
"""
|
||||
Load an image that was previously saved using
|
||||
|
|
|
@ -5,7 +5,7 @@ import six
|
|||
|
||||
from ..api import APIClient
|
||||
from ..constants import DEFAULT_DATA_CHUNK_SIZE
|
||||
from ..errors import BuildError, ImageLoadError
|
||||
from ..errors import BuildError, ImageLoadError, InvalidArgument
|
||||
from ..utils import parse_repository_tag
|
||||
from ..utils.json_stream import json_stream
|
||||
from .resource import Collection, Model
|
||||
|
@ -105,6 +105,81 @@ class Image(Model):
|
|||
return self.client.api.tag(self.id, repository, tag=tag, **kwargs)
|
||||
|
||||
|
||||
class RegistryData(Model):
|
||||
"""
|
||||
Image metadata stored on the registry, including available platforms.
|
||||
"""
|
||||
def __init__(self, image_name, *args, **kwargs):
|
||||
super(RegistryData, self).__init__(*args, **kwargs)
|
||||
self.image_name = image_name
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
"""
|
||||
The ID of the object.
|
||||
"""
|
||||
return self.attrs['Descriptor']['digest']
|
||||
|
||||
@property
|
||||
def short_id(self):
|
||||
"""
|
||||
The ID of the image truncated to 10 characters, plus the ``sha256:``
|
||||
prefix.
|
||||
"""
|
||||
return self.id[:17]
|
||||
|
||||
def pull(self, platform=None):
|
||||
"""
|
||||
Pull the image digest.
|
||||
|
||||
Args:
|
||||
platform (str): The platform to pull the image for.
|
||||
Default: ``None``
|
||||
|
||||
Returns:
|
||||
(:py:class:`Image`): A reference to the pulled image.
|
||||
"""
|
||||
repository, _ = parse_repository_tag(self.image_name)
|
||||
return self.collection.pull(repository, tag=self.id, platform=platform)
|
||||
|
||||
def has_platform(self, platform):
|
||||
"""
|
||||
Check whether the given platform identifier is available for this
|
||||
digest.
|
||||
|
||||
Args:
|
||||
platform (str or dict): A string using the ``os[/arch[/variant]]``
|
||||
format, or a platform dictionary.
|
||||
|
||||
Returns:
|
||||
(bool): ``True`` if the platform is recognized as available,
|
||||
``False`` otherwise.
|
||||
|
||||
Raises:
|
||||
:py:class:`docker.errors.InvalidArgument`
|
||||
If the platform argument is not a valid descriptor.
|
||||
"""
|
||||
if platform and not isinstance(platform, dict):
|
||||
parts = platform.split('/')
|
||||
if len(parts) > 3 or len(parts) < 1:
|
||||
raise InvalidArgument(
|
||||
'"{0}" is not a valid platform descriptor'.format(platform)
|
||||
)
|
||||
platform = {'os': parts[0]}
|
||||
if len(parts) > 2:
|
||||
platform['variant'] = parts[2]
|
||||
if len(parts) > 1:
|
||||
platform['architecture'] = parts[1]
|
||||
return normalize_platform(
|
||||
platform, self.client.version()
|
||||
) in self.attrs['Platforms']
|
||||
|
||||
def reload(self):
|
||||
self.attrs = self.client.api.inspect_distribution(self.image_name)
|
||||
|
||||
reload.__doc__ = Model.reload.__doc__
|
||||
|
||||
|
||||
class ImageCollection(Collection):
|
||||
model = Image
|
||||
|
||||
|
@ -219,6 +294,26 @@ class ImageCollection(Collection):
|
|||
"""
|
||||
return self.prepare_model(self.client.api.inspect_image(name))
|
||||
|
||||
def get_registry_data(self, name):
|
||||
"""
|
||||
Gets the registry data for an image.
|
||||
|
||||
Args:
|
||||
name (str): The name of the image.
|
||||
|
||||
Returns:
|
||||
(:py:class:`RegistryData`): The data object.
|
||||
Raises:
|
||||
:py:class:`docker.errors.APIError`
|
||||
If the server returns an error.
|
||||
"""
|
||||
return RegistryData(
|
||||
image_name=name,
|
||||
attrs=self.client.api.inspect_distribution(name),
|
||||
client=self.client,
|
||||
collection=self,
|
||||
)
|
||||
|
||||
def list(self, name=None, all=False, filters=None):
|
||||
"""
|
||||
List images on the server.
|
||||
|
@ -336,3 +431,13 @@ class ImageCollection(Collection):
|
|||
def prune(self, filters=None):
|
||||
return self.client.api.prune_images(filters=filters)
|
||||
prune.__doc__ = APIClient.prune_images.__doc__
|
||||
|
||||
|
||||
def normalize_platform(platform, engine_info):
|
||||
if platform is None:
|
||||
platform = {}
|
||||
if 'os' not in platform:
|
||||
platform['os'] = engine_info['Os']
|
||||
if 'architecture' not in platform:
|
||||
platform['architecture'] = engine_info['Arch']
|
||||
return platform
|
||||
|
|
|
@ -12,6 +12,7 @@ Methods available on ``client.images``:
|
|||
|
||||
.. automethod:: build
|
||||
.. automethod:: get
|
||||
.. automethod:: get_registry_data
|
||||
.. automethod:: list(**kwargs)
|
||||
.. automethod:: load
|
||||
.. automethod:: prune
|
||||
|
@ -41,3 +42,21 @@ Image objects
|
|||
.. automethod:: reload
|
||||
.. automethod:: save
|
||||
.. automethod:: tag
|
||||
|
||||
RegistryData objects
|
||||
--------------------
|
||||
|
||||
.. autoclass:: RegistryData()
|
||||
|
||||
.. py:attribute:: attrs
|
||||
|
||||
The raw representation of this object from the server.
|
||||
|
||||
.. autoattribute:: id
|
||||
.. autoattribute:: short_id
|
||||
|
||||
|
||||
|
||||
.. automethod:: has_platform
|
||||
.. automethod:: pull
|
||||
.. automethod:: reload
|
||||
|
|
|
@ -357,3 +357,12 @@ class SaveLoadImagesTest(BaseAPIIntegrationTest):
|
|||
success = True
|
||||
break
|
||||
assert success is True
|
||||
|
||||
|
||||
@requires_api_version('1.30')
|
||||
class InspectDistributionTest(BaseAPIIntegrationTest):
|
||||
def test_inspect_distribution(self):
|
||||
data = self.client.inspect_distribution('busybox:latest')
|
||||
assert data is not None
|
||||
assert 'Platforms' in data
|
||||
assert {'os': 'linux', 'architecture': 'amd64'} in data['Platforms']
|
||||
|
|
Loading…
Reference in New Issue