From cec152db5f679bc61c2093959bd9109cb9abb169 Mon Sep 17 00:00:00 2001 From: aiordache Date: Tue, 15 Sep 2020 18:42:19 +0200 Subject: [PATCH] Set image default tag on pull Signed-off-by: aiordache --- docker/api/image.py | 11 ++++++++--- docker/models/images.py | 21 +++++++++++---------- tests/integration/api_image_test.py | 4 ++-- tests/integration/models_images_test.py | 2 +- tests/unit/api_image_test.py | 4 ++-- tests/unit/models_containers_test.py | 2 +- tests/unit/models_images_test.py | 24 ++++++++++++++++++++---- 7 files changed, 45 insertions(+), 23 deletions(-) diff --git a/docker/api/image.py b/docker/api/image.py index 11c8cf75..dcce0acb 100644 --- a/docker/api/image.py +++ b/docker/api/image.py @@ -343,7 +343,7 @@ class ImageApiMixin(object): return self._result(self._post(url, params=params), True) def pull(self, repository, tag=None, stream=False, auth_config=None, - decode=False, platform=None): + decode=False, platform=None, all_tags=False): """ Pulls an image. Similar to the ``docker pull`` command. @@ -358,6 +358,7 @@ class ImageApiMixin(object): decode (bool): Decode the JSON data from the server into dicts. Only applies with ``stream=True`` platform (str): Platform in the format ``os[/arch[/variant]]`` + all_tags (bool): Pull all image tags. Returns: (generator or str): The output @@ -382,8 +383,12 @@ class ImageApiMixin(object): } """ - if not tag: - repository, tag = utils.parse_repository_tag(repository) + repository, image_tag = utils.parse_repository_tag(repository) + tag = tag or image_tag or 'latest' + + if all_tags: + tag = None + registry, repo_name = auth.resolve_repository_name(repository) params = { diff --git a/docker/models/images.py b/docker/models/images.py index 757a5a47..d2c5835a 100644 --- a/docker/models/images.py +++ b/docker/models/images.py @@ -395,12 +395,12 @@ class ImageCollection(Collection): return [self.get(i) for i in images] - def pull(self, repository, tag=None, **kwargs): + def pull(self, repository, tag=None, all_tags=False, **kwargs): """ Pull an image of the given name and return it. Similar to the ``docker pull`` command. - If no tag is specified, all tags from that repository will be - pulled. + If ``all_tags`` is set, the ``tag`` parameter is ignored and all image + tags will be pulled. If you want to get the raw pull output, use the :py:meth:`~docker.api.image.ImageApiMixin.pull` method in the @@ -413,10 +413,11 @@ class ImageCollection(Collection): config for this request. ``auth_config`` should contain the ``username`` and ``password`` keys to be valid. platform (str): Platform in the format ``os[/arch[/variant]]`` + all_tags (bool): Pull all image tags Returns: (:py:class:`Image` or list): The image that has been pulled. - If no ``tag`` was specified, the method will return a list + If ``tag`` is None, the method will return a list of :py:class:`Image` objects belonging to this repository. Raises: @@ -426,13 +427,13 @@ class ImageCollection(Collection): Example: >>> # Pull the image tagged `latest` in the busybox repo - >>> image = client.images.pull('busybox:latest') + >>> image = client.images.pull('busybox') >>> # Pull all tags in the busybox repo - >>> images = client.images.pull('busybox') + >>> images = client.images.pull('busybox', all_tags=True) """ - if not tag: - repository, tag = parse_repository_tag(repository) + repository, image_tag = parse_repository_tag(repository) + tag = tag or image_tag or 'latest' if 'stream' in kwargs: warnings.warn( @@ -442,14 +443,14 @@ class ImageCollection(Collection): del kwargs['stream'] pull_log = self.client.api.pull( - repository, tag=tag, stream=True, **kwargs + repository, tag=tag, stream=True, all_tags=all_tags, **kwargs ) for _ in pull_log: # We don't do anything with the logs, but we need # to keep the connection alive and wait for the image # to be pulled. pass - if tag: + if not all_tags: return self.get('{0}{2}{1}'.format( repository, tag, '@' if tag.startswith('sha256:') else ':' )) diff --git a/tests/integration/api_image_test.py b/tests/integration/api_image_test.py index 2bc96abf..37e26a3f 100644 --- a/tests/integration/api_image_test.py +++ b/tests/integration/api_image_test.py @@ -42,7 +42,7 @@ class PullImageTest(BaseAPIIntegrationTest): self.client.remove_image('hello-world') except docker.errors.APIError: pass - res = self.client.pull('hello-world', tag='latest') + res = self.client.pull('hello-world') self.tmp_imgs.append('hello-world') assert type(res) == six.text_type assert len(self.client.images('hello-world')) >= 1 @@ -55,7 +55,7 @@ class PullImageTest(BaseAPIIntegrationTest): except docker.errors.APIError: pass stream = self.client.pull( - 'hello-world', tag='latest', stream=True, decode=True) + 'hello-world', stream=True, decode=True) self.tmp_imgs.append('hello-world') for chunk in stream: assert isinstance(chunk, dict) diff --git a/tests/integration/models_images_test.py b/tests/integration/models_images_test.py index 223d102f..0d60f37b 100644 --- a/tests/integration/models_images_test.py +++ b/tests/integration/models_images_test.py @@ -86,7 +86,7 @@ class ImageCollectionTest(BaseIntegrationTest): def test_pull_multiple(self): client = docker.from_env(version=TEST_API_VERSION) - images = client.images.pull('hello-world') + images = client.images.pull('hello-world', all_tags=True) assert len(images) >= 1 assert any([ 'hello-world:latest' in img.attrs['RepoTags'] for img in images diff --git a/tests/unit/api_image_test.py b/tests/unit/api_image_test.py index 1e2315db..4b4fb977 100644 --- a/tests/unit/api_image_test.py +++ b/tests/unit/api_image_test.py @@ -67,7 +67,7 @@ class ImageTest(BaseAPIClientTest): args = fake_request.call_args assert args[0][1] == url_prefix + 'images/create' assert args[1]['params'] == { - 'tag': None, 'fromImage': 'joffrey/test001' + 'tag': 'latest', 'fromImage': 'joffrey/test001' } assert not args[1]['stream'] @@ -77,7 +77,7 @@ class ImageTest(BaseAPIClientTest): args = fake_request.call_args assert args[0][1] == url_prefix + 'images/create' assert args[1]['params'] == { - 'tag': None, 'fromImage': 'joffrey/test001' + 'tag': 'latest', 'fromImage': 'joffrey/test001' } assert args[1]['stream'] diff --git a/tests/unit/models_containers_test.py b/tests/unit/models_containers_test.py index c9f73f37..c7aa46b2 100644 --- a/tests/unit/models_containers_test.py +++ b/tests/unit/models_containers_test.py @@ -233,7 +233,7 @@ class ContainerCollectionTest(unittest.TestCase): assert container.id == FAKE_CONTAINER_ID client.api.pull.assert_called_with( - 'alpine', platform=None, tag=None, stream=True + 'alpine', platform=None, tag='latest', all_tags=False, stream=True ) def test_run_with_error(self): diff --git a/tests/unit/models_images_test.py b/tests/unit/models_images_test.py index fd894ab7..e3d070c0 100644 --- a/tests/unit/models_images_test.py +++ b/tests/unit/models_images_test.py @@ -44,9 +44,25 @@ class ImageCollectionTest(unittest.TestCase): def test_pull(self): client = make_fake_client() - image = client.images.pull('test_image:latest') + image = client.images.pull('test_image:test') client.api.pull.assert_called_with( - 'test_image', tag='latest', stream=True + 'test_image', tag='test', all_tags=False, stream=True + ) + client.api.inspect_image.assert_called_with('test_image:test') + assert isinstance(image, Image) + assert image.id == FAKE_IMAGE_ID + + def test_pull_tag_precedence(self): + client = make_fake_client() + image = client.images.pull('test_image:latest', tag='test') + client.api.pull.assert_called_with( + 'test_image', tag='test', all_tags=False, stream=True + ) + client.api.inspect_image.assert_called_with('test_image:test') + + image = client.images.pull('test_image') + client.api.pull.assert_called_with( + 'test_image', tag='latest', all_tags=False, stream=True ) client.api.inspect_image.assert_called_with('test_image:latest') assert isinstance(image, Image) @@ -54,9 +70,9 @@ class ImageCollectionTest(unittest.TestCase): def test_pull_multiple(self): client = make_fake_client() - images = client.images.pull('test_image') + images = client.images.pull('test_image', all_tags=True) client.api.pull.assert_called_with( - 'test_image', tag=None, stream=True + 'test_image', tag='latest', all_tags=True, stream=True ) client.api.images.assert_called_with( all=False, name='test_image', filters=None