Kaydet (Commit) 7117855f authored tarafından adw1n's avatar adw1n Kaydeden (comit) Joffrey F

Fix pulling images with `stream=True`

Pulling an image with option `stream=True` like this:
```
client.api.pull('docker.io/user/repo_name', tag='latest', stream=True)
```
without consuming the generator oftentimes results in premature drop of the connection. Docker daemon tries to send progress of pulling the image to the client, but it encounters an error (broken pipe) and therefore cancells the pull action:
```
Thread 1 "dockerd-dev" received signal SIGPIPE, Broken pipe.
ERRO[2018-09-03T05:12:35.746497638+02:00] Not continuing with pull after error: context canceled
```
As described in issue #2116, even though client receives response with status code 200, image is not pulled.

Closes #2116
Signed-off-by: 's avatarPrzemysław Adamek <adw1n@users.noreply.github.com>
üst f9505da1
...@@ -334,7 +334,8 @@ class ImageApiMixin(object): ...@@ -334,7 +334,8 @@ class ImageApiMixin(object):
Args: Args:
repository (str): The repository to pull repository (str): The repository to pull
tag (str): The tag to pull tag (str): The tag to pull
stream (bool): Stream the output as a generator stream (bool): Stream the output as a generator. Make sure to
consume the generator, otherwise pull might get cancelled.
auth_config (dict): Override the credentials that auth_config (dict): Override the credentials that
:py:meth:`~docker.api.daemon.DaemonApiMixin.login` has set for :py:meth:`~docker.api.daemon.DaemonApiMixin.login` has set for
this request. ``auth_config`` should contain the ``username`` this request. ``auth_config`` should contain the ``username``
......
...@@ -425,6 +425,7 @@ class ImageCollection(Collection): ...@@ -425,6 +425,7 @@ class ImageCollection(Collection):
if not tag: if not tag:
repository, tag = parse_repository_tag(repository) repository, tag = parse_repository_tag(repository)
kwargs['stream'] = False
self.client.api.pull(repository, tag=tag, **kwargs) self.client.api.pull(repository, tag=tag, **kwargs)
if tag: if tag:
return self.get('{0}{2}{1}'.format( return self.get('{0}{2}{1}'.format(
......
...@@ -232,7 +232,8 @@ class ContainerCollectionTest(unittest.TestCase): ...@@ -232,7 +232,8 @@ class ContainerCollectionTest(unittest.TestCase):
container = client.containers.run('alpine', 'sleep 300', detach=True) container = client.containers.run('alpine', 'sleep 300', detach=True)
assert container.id == FAKE_CONTAINER_ID assert container.id == FAKE_CONTAINER_ID
client.api.pull.assert_called_with('alpine', platform=None, tag=None) client.api.pull.assert_called_with('alpine', platform=None, tag=None,
stream=False)
def test_run_with_error(self): def test_run_with_error(self):
client = make_fake_client() client = make_fake_client()
......
...@@ -43,7 +43,8 @@ class ImageCollectionTest(unittest.TestCase): ...@@ -43,7 +43,8 @@ class ImageCollectionTest(unittest.TestCase):
def test_pull(self): def test_pull(self):
client = make_fake_client() client = make_fake_client()
image = client.images.pull('test_image:latest') image = client.images.pull('test_image:latest')
client.api.pull.assert_called_with('test_image', tag='latest') client.api.pull.assert_called_with('test_image', tag='latest',
stream=False)
client.api.inspect_image.assert_called_with('test_image:latest') client.api.inspect_image.assert_called_with('test_image:latest')
assert isinstance(image, Image) assert isinstance(image, Image)
assert image.id == FAKE_IMAGE_ID assert image.id == FAKE_IMAGE_ID
...@@ -51,7 +52,8 @@ class ImageCollectionTest(unittest.TestCase): ...@@ -51,7 +52,8 @@ class ImageCollectionTest(unittest.TestCase):
def test_pull_multiple(self): def test_pull_multiple(self):
client = make_fake_client() client = make_fake_client()
images = client.images.pull('test_image') images = client.images.pull('test_image')
client.api.pull.assert_called_with('test_image', tag=None) client.api.pull.assert_called_with('test_image', tag=None,
stream=False)
client.api.images.assert_called_with( client.api.images.assert_called_with(
all=False, name='test_image', filters=None all=False, name='test_image', filters=None
) )
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment