service: detailed error messages for create and start

Fixes: #3355

Signed-off-by: Tomas Tomecek <ttomecek@redhat.com>
This commit is contained in:
Tomas Tomecek 2016-04-21 14:03:02 +02:00
parent c3fd6a8f4d
commit fea970dff3
5 changed files with 28 additions and 4 deletions

View File

@ -32,6 +32,7 @@ from ..service import BuildError
from ..service import ConvergenceStrategy from ..service import ConvergenceStrategy
from ..service import ImageType from ..service import ImageType
from ..service import NeedsBuildError from ..service import NeedsBuildError
from ..service import OperationFailedError
from .command import get_config_from_options from .command import get_config_from_options
from .command import project_from_options from .command import project_from_options
from .docopt_command import DocoptDispatcher from .docopt_command import DocoptDispatcher
@ -61,7 +62,8 @@ def main():
except (KeyboardInterrupt, signals.ShutdownException): except (KeyboardInterrupt, signals.ShutdownException):
log.error("Aborting.") log.error("Aborting.")
sys.exit(1) sys.exit(1)
except (UserError, NoSuchService, ConfigurationError, ProjectError) as e: except (UserError, NoSuchService, ConfigurationError,
ProjectError, OperationFailedError) as e:
log.error(e.msg) log.error(e.msg)
sys.exit(1) sys.exit(1)
except BuildError as e: except BuildError as e:

7
compose/errors.py Normal file
View File

@ -0,0 +1,7 @@
from __future__ import absolute_import
from __future__ import unicode_literals
class OperationFailedError(Exception):
def __init__(self, reason):
self.msg = reason

View File

@ -12,6 +12,7 @@ from six.moves.queue import Empty
from six.moves.queue import Queue from six.moves.queue import Queue
from compose.cli.signals import ShutdownException from compose.cli.signals import ShutdownException
from compose.errors import OperationFailedError
from compose.utils import get_output_stream from compose.utils import get_output_stream
@ -47,6 +48,9 @@ def parallel_execute(objects, func, get_name, msg, get_deps=None):
elif isinstance(exception, APIError): elif isinstance(exception, APIError):
errors[get_name(obj)] = exception.explanation errors[get_name(obj)] = exception.explanation
writer.write(get_name(obj), 'error') writer.write(get_name(obj), 'error')
elif isinstance(exception, OperationFailedError):
errors[get_name(obj)] = exception.msg
writer.write(get_name(obj), 'error')
elif isinstance(exception, UpstreamError): elif isinstance(exception, UpstreamError):
writer.write(get_name(obj), 'error') writer.write(get_name(obj), 'error')
else: else:

View File

@ -27,6 +27,7 @@ from .const import LABEL_PROJECT
from .const import LABEL_SERVICE from .const import LABEL_SERVICE
from .const import LABEL_VERSION from .const import LABEL_VERSION
from .container import Container from .container import Container
from .errors import OperationFailedError
from .parallel import parallel_execute from .parallel import parallel_execute
from .parallel import parallel_start from .parallel import parallel_start
from .progress_stream import stream_output from .progress_stream import stream_output
@ -278,7 +279,11 @@ class Service(object):
if 'name' in container_options and not quiet: if 'name' in container_options and not quiet:
log.info("Creating %s" % container_options['name']) log.info("Creating %s" % container_options['name'])
try:
return Container.create(self.client, **container_options) return Container.create(self.client, **container_options)
except APIError as ex:
raise OperationFailedError("Cannot create container for service %s: %s" %
(self.name, ex.explanation))
def ensure_image_exists(self, do_build=BuildAction.none): def ensure_image_exists(self, do_build=BuildAction.none):
if self.can_be_built() and do_build == BuildAction.force: if self.can_be_built() and do_build == BuildAction.force:
@ -448,7 +453,10 @@ class Service(object):
def start_container(self, container): def start_container(self, container):
self.connect_container_to_networks(container) self.connect_container_to_networks(container)
try:
container.start() container.start()
except APIError as ex:
raise OperationFailedError("Cannot start service %s: %s" % (self.name, ex.explanation))
return container return container
def connect_container_to_networks(self, container): def connect_container_to_networks(self, container):

View File

@ -738,7 +738,10 @@ class ServiceTest(DockerClientTestCase):
self.assertEqual(len(service.containers()), 1) self.assertEqual(len(service.containers()), 1)
self.assertTrue(service.containers()[0].is_running) self.assertTrue(service.containers()[0].is_running)
self.assertIn("ERROR: for composetest_web_2 Boom", mock_stderr.getvalue()) self.assertIn(
"ERROR: for composetest_web_2 Cannot create container for service web: Boom",
mock_stderr.getvalue()
)
def test_scale_with_unexpected_exception(self): def test_scale_with_unexpected_exception(self):
"""Test that when scaling if the API returns an error, that is not of type """Test that when scaling if the API returns an error, that is not of type