diff options
author | Joffrey F <joffrey@docker.com> | 2017-12-14 15:12:08 -0800 |
---|---|---|
committer | Joffrey F <joffrey@docker.com> | 2017-12-14 16:53:44 -0800 |
commit | 6b8dfe42499345aaa1701d835ea0a9b86a00f1a6 (patch) | |
tree | a93eb2ddda39d3f60cd382927baedadce96ece16 | |
parent | 8cfd4cb39f5d50ee0080e5c038809425784fd516 (diff) | |
download | docker-py-1813-run-autoremove.tar.gz |
Retrieve container logs before container exits / is removed1813-run-autoremove
Signed-off-by: Joffrey F <joffrey@docker.com>
-rw-r--r-- | docker/models/containers.py | 29 | ||||
-rw-r--r-- | tests/integration/models_containers_test.py | 23 | ||||
-rw-r--r-- | tests/unit/fake_api_client.py | 2 | ||||
-rw-r--r-- | tests/unit/models_containers_test.py | 7 |
4 files changed, 43 insertions, 18 deletions
diff --git a/docker/models/containers.py b/docker/models/containers.py index 4e3d218..f16b7cd 100644 --- a/docker/models/containers.py +++ b/docker/models/containers.py @@ -629,6 +629,9 @@ class ContainerCollection(Collection): (e.g. ``SIGINT``). storage_opt (dict): Storage driver options per container as a key-value mapping. + stream (bool): If true and ``detach`` is false, return a log + generator instead of a string. Ignored if ``detach`` is true. + Default: ``False``. sysctls (dict): Kernel parameters to set in the container. tmpfs (dict): Temporary filesystems to mount, as a dictionary mapping a path inside the container to options for that path. @@ -696,6 +699,7 @@ class ContainerCollection(Collection): """ if isinstance(image, Image): image = image.id + stream = kwargs.pop('stream', False) detach = kwargs.pop("detach", False) if detach and remove: if version_gte(self.client.api._version, '1.25'): @@ -723,23 +727,28 @@ class ContainerCollection(Collection): if detach: return container - exit_status = container.wait() - if exit_status != 0: - stdout = False - stderr = True - logging_driver = container.attrs['HostConfig']['LogConfig']['Type'] + out = None if logging_driver == 'json-file' or logging_driver == 'journald': - out = container.logs(stdout=stdout, stderr=stderr) - else: - out = None + out = container.logs( + stdout=stdout, stderr=stderr, stream=True, follow=True + ) + + exit_status = container.wait() + if exit_status != 0: + out = container.logs(stdout=False, stderr=True) if remove: container.remove() if exit_status != 0: - raise ContainerError(container, exit_status, command, image, out) - return out + raise ContainerError( + container, exit_status, command, image, out + ) + + return out if stream or out is None else b''.join( + [line for line in out] + ) def create(self, image, command=None, **kwargs): """ diff --git a/tests/integration/models_containers_test.py b/tests/integration/models_containers_test.py index ce3349b..7707ae2 100644 --- a/tests/integration/models_containers_test.py +++ b/tests/integration/models_containers_test.py @@ -1,7 +1,7 @@ import docker import tempfile from .base import BaseIntegrationTest, TEST_API_VERSION -from ..helpers import random_name +from ..helpers import random_name, requires_api_version class ContainerCollectionTest(BaseIntegrationTest): @@ -95,7 +95,7 @@ class ContainerCollectionTest(BaseIntegrationTest): "alpine", "echo hello", log_config=dict(type='none') ) - self.assertEqual(out, None) + assert out is None def test_run_with_json_file_driver(self): client = docker.from_env(version=TEST_API_VERSION) @@ -104,7 +104,24 @@ class ContainerCollectionTest(BaseIntegrationTest): "alpine", "echo hello", log_config=dict(type='json-file') ) - self.assertEqual(out, b'hello\n') + assert out == b'hello\n' + + @requires_api_version('1.25') + def test_run_with_auto_remove(self): + client = docker.from_env(version=TEST_API_VERSION) + out = client.containers.run( + 'alpine', 'echo hello', auto_remove=True + ) + assert out == b'hello\n' + + def test_run_with_streamed_logs(self): + client = docker.from_env(version=TEST_API_VERSION) + out = client.containers.run( + 'alpine', 'sh -c "echo hello && echo world"', stream=True + ) + logs = [line for line in out] + assert logs[0] == b'hello\n' + assert logs[1] == b'world\n' def test_get(self): client = docker.from_env(version=TEST_API_VERSION) diff --git a/tests/unit/fake_api_client.py b/tests/unit/fake_api_client.py index 47890ac..f908355 100644 --- a/tests/unit/fake_api_client.py +++ b/tests/unit/fake_api_client.py @@ -43,7 +43,7 @@ def make_fake_api_client(): fake_api.get_fake_inspect_container()[1], 'inspect_image.return_value': fake_api.get_fake_inspect_image()[1], 'inspect_network.return_value': fake_api.get_fake_network()[1], - 'logs.return_value': 'hello world\n', + 'logs.return_value': [b'hello world\n'], 'networks.return_value': fake_api.get_fake_network_list()[1], 'start.return_value': None, 'wait.return_value': 0, diff --git a/tests/unit/models_containers_test.py b/tests/unit/models_containers_test.py index 5eaa45a..a479e83 100644 --- a/tests/unit/models_containers_test.py +++ b/tests/unit/models_containers_test.py @@ -12,7 +12,7 @@ class ContainerCollectionTest(unittest.TestCase): client = make_fake_client() out = client.containers.run("alpine", "echo hello world") - assert out == 'hello world\n' + assert out == b'hello world\n' client.api.create_container.assert_called_with( image="alpine", @@ -24,9 +24,8 @@ class ContainerCollectionTest(unittest.TestCase): client.api.start.assert_called_with(FAKE_CONTAINER_ID) client.api.wait.assert_called_with(FAKE_CONTAINER_ID) client.api.logs.assert_called_with( - FAKE_CONTAINER_ID, - stderr=False, - stdout=True + FAKE_CONTAINER_ID, stderr=False, stdout=True, stream=True, + follow=True ) def test_create_container_args(self): |