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: Przemysław Adamek <adw1n@users.noreply.github.com>
This commit is contained in:
adw1n 2018-09-03 05:54:12 +02:00 committed by Joffrey F
parent e1e4048753
commit a74d546864
4 changed files with 9 additions and 4 deletions

View File

@ -334,7 +334,8 @@ class ImageApiMixin(object):
Args:
repository (str): The repository 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
:py:meth:`~docker.api.daemon.DaemonApiMixin.login` has set for
this request. ``auth_config`` should contain the ``username``

View File

@ -425,6 +425,7 @@ class ImageCollection(Collection):
if not tag:
repository, tag = parse_repository_tag(repository)
kwargs['stream'] = False
self.client.api.pull(repository, tag=tag, **kwargs)
if tag:
return self.get('{0}{2}{1}'.format(

View File

@ -232,7 +232,8 @@ class ContainerCollectionTest(unittest.TestCase):
container = client.containers.run('alpine', 'sleep 300', detach=True)
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):
client = make_fake_client()

View File

@ -43,7 +43,8 @@ class ImageCollectionTest(unittest.TestCase):
def test_pull(self):
client = make_fake_client()
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')
assert isinstance(image, Image)
assert image.id == FAKE_IMAGE_ID
@ -51,7 +52,8 @@ class ImageCollectionTest(unittest.TestCase):
def test_pull_multiple(self):
client = make_fake_client()
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(
all=False, name='test_image', filters=None
)