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 ImageType
from ..service import NeedsBuildError
from ..service import OperationFailedError
from .command import get_config_from_options
from .command import project_from_options
from .docopt_command import DocoptDispatcher
@ -61,7 +62,8 @@ def main():
except (KeyboardInterrupt, signals.ShutdownException):
log.error("Aborting.")
sys.exit(1)
except (UserError, NoSuchService, ConfigurationError, ProjectError) as e:
except (UserError, NoSuchService, ConfigurationError,
ProjectError, OperationFailedError) as e:
log.error(e.msg)
sys.exit(1)
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 compose.cli.signals import ShutdownException
from compose.errors import OperationFailedError
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):
errors[get_name(obj)] = exception.explanation
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):
writer.write(get_name(obj), 'error')
else:

View File

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

View File

@ -738,7 +738,10 @@ class ServiceTest(DockerClientTestCase):
self.assertEqual(len(service.containers()), 1)
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):
"""Test that when scaling if the API returns an error, that is not of type