diff --git a/compose/service.py b/compose/service.py index d329be979..024e7fbde 100644 --- a/compose/service.py +++ b/compose/service.py @@ -60,6 +60,7 @@ from .utils import parse_bytes from .utils import parse_seconds_float from .utils import truncate_id from .utils import unique_everseen +from compose.cli.utils import binarystr_to_unicode if six.PY2: import subprocess32 as subprocess @@ -343,7 +344,7 @@ class Service(object): return Container.create(self.client, **container_options) except APIError as ex: raise OperationFailedError("Cannot create container for service %s: %s" % - (self.name, ex.explanation)) + (self.name, binarystr_to_unicode(ex.explanation))) def ensure_image_exists(self, do_build=BuildAction.none, silent=False, cli=False): if self.can_be_built() and do_build == BuildAction.force: @@ -624,9 +625,10 @@ class Service(object): try: container.start() except APIError as ex: - if "driver failed programming external connectivity" in ex.explanation: + expl = binarystr_to_unicode(ex.explanation) + if "driver failed programming external connectivity" in expl: log.warn("Host is already in use by another container") - raise OperationFailedError("Cannot start service %s: %s" % (self.name, ex.explanation)) + raise OperationFailedError("Cannot start service %s: %s" % (self.name, expl)) return container @property diff --git a/tests/unit/service_test.py b/tests/unit/service_test.py index a6a633db8..592e22f75 100644 --- a/tests/unit/service_test.py +++ b/tests/unit/service_test.py @@ -521,7 +521,37 @@ class ServiceTest(unittest.TestCase): assert 'was built because it did not already exist' in args[0] assert self.mock_client.build.call_count == 1 - self.mock_client.build.call_args[1]['tag'] == 'default_foo' + assert self.mock_client.build.call_args[1]['tag'] == 'default_foo' + + def test_create_container_binary_string_error(self): + service = Service('foo', client=self.mock_client, build={'context': '.'}) + service.image = lambda: {'Id': 'abc123'} + + self.mock_client.create_container.side_effect = APIError(None, + None, + b"Test binary string explanation") + with pytest.raises(OperationFailedError) as ex: + service.create_container() + + assert ex.value.msg == "Cannot create container for service foo: Test binary string explanation" + + def test_start_binary_string_error(self): + service = Service('foo', client=self.mock_client) + container = Container(self.mock_client, {'Id': 'abc123'}) + + self.mock_client.start.side_effect = APIError(None, + None, + b"Test binary string explanation with " + b"driver failed programming external " + b"connectivity") + with mock.patch('compose.service.log', autospec=True) as mock_log: + with pytest.raises(OperationFailedError) as ex: + service.start_container(container) + + assert ex.value.msg == "Cannot start service foo: " \ + "Test binary string explanation " \ + "with driver failed programming external connectivity" + mock_log.warn.assert_called_once_with("Host is already in use by another container") def test_ensure_image_exists_no_build(self): service = Service('foo', client=self.mock_client, build={'context': '.'})