diff --git a/heat/common/exception.py b/heat/common/exception.py index 875b4287a2..1e2f85e51a 100644 --- a/heat/common/exception.py +++ b/heat/common/exception.py @@ -246,5 +246,17 @@ class WatchRuleNotFound(OpenstackException): message = _("The Watch Rule (%(watch_name)s) could not be found.") +class ResourceFailure(OpenstackException): + message = _("%(exc_type)s: %(message)s") + + def __init__(self, exception): + if isinstance(exception, ResourceFailure): + exception = getattr(exception, 'exc', exception) + self.exc = exception + exc_type = type(exception).__name__ + super(ResourceFailure, self).__init__(exc_type=exc_type, + message=str(exception)) + + class NestedResourceFailure(OpenstackException): message = _("%(message)s") diff --git a/heat/engine/parser.py b/heat/engine/parser.py index 203c5bc864..257f3d11d8 100644 --- a/heat/engine/parser.py +++ b/heat/engine/parser.py @@ -275,12 +275,12 @@ class Stack(object): try: for res in self: if stack_status != self.CREATE_FAILED: - result = res.create() - if result: + try: + res.create() + except exception.ResourceFailure as ex: stack_status = self.CREATE_FAILED reason = 'Resource %s failed with: %s' % (str(res), - result) - + str(ex)) else: res.state_set(res.CREATE_FAILED, 'Stack creation aborted') @@ -366,10 +366,11 @@ class Stack(object): self[res.name] = res self.dependencies = self._get_dependencies( self.resources.itervalues()) - result = self[res.name].create() - if result: + try: + self[res.name].create() + except exception.ResourceFailure as ex: logger.error("Failed to add %s : %s" % - (res.name, result)) + (res.name, str(ex))) raise exception.ResourceUpdateFailed( resource_name=res.name) @@ -418,10 +419,11 @@ class Stack(object): self[res.name] = res self.dependencies = self._get_dependencies( self.resources.itervalues()) - result = self[res.name].create() - if result: + try: + self[res.name].create() + except exception.ResourceFailure as ex: logger.error("Failed to create %s : %s" % - (res.name, result)) + (res.name, str(ex))) raise exception.ResourceUpdateFailed( resource_name=res.name) else: @@ -541,7 +543,7 @@ class Stack(object): if not failed: try: res.create() - except Exception as ex: + except exception.ResourceFailure as ex: logger.exception('create') failed = True else: diff --git a/heat/engine/resource.py b/heat/engine/resource.py index bd63cf5b0f..3a60c0a31a 100644 --- a/heat/engine/resource.py +++ b/heat/engine/resource.py @@ -324,8 +324,9 @@ class Resource(object): raise except Exception as ex: logger.exception('create %s', str(self)) - self.state_set(self.CREATE_FAILED, str(ex)) - return str(ex) or "Error : %s" % type(ex) + failure = exception.ResourceFailure(ex) + self.state_set(self.CREATE_FAILED, str(failure)) + raise failure else: self.state_set(self.CREATE_COMPLETE) diff --git a/heat/engine/resources/autoscaling.py b/heat/engine/resources/autoscaling.py index ec716d542b..ed1ca5c5de 100644 --- a/heat/engine/resources/autoscaling.py +++ b/heat/engine/resources/autoscaling.py @@ -192,9 +192,11 @@ class InstanceGroup(resource.Resource): self.resource_id_set(','.join(inst_list)) logger.info('Creating Autoscaling instance %s' % name) - error_str = inst.create() - if raise_on_error and error_str is not None: - raise exception.NestedResourceFailure(message=error_str) + try: + inst.create() + except exception.ResourceFailure as ex: + if raise_on_error: + raise return inst diff --git a/heat/tests/test_instance_group.py b/heat/tests/test_instance_group.py index bcf4faa295..ecd3c87b90 100644 --- a/heat/tests/test_instance_group.py +++ b/heat/tests/test_instance_group.py @@ -121,7 +121,7 @@ class InstanceGroupTest(unittest.TestCase): self.m.ReplayAll() - self.assertNotEqual(resource.create(), None) + self.assertRaises(exception.ResourceFailure, resource.create) self.assertEqual(asc.InstanceGroup.CREATE_FAILED, resource.state) self.m.VerifyAll() diff --git a/heat/tests/test_resource.py b/heat/tests/test_resource.py index ced23c920a..fc38b1b0ab 100644 --- a/heat/tests/test_resource.py +++ b/heat/tests/test_resource.py @@ -242,7 +242,7 @@ class ResourceTest(unittest.TestCase): res = generic_rsrc.GenericResource(rname, tmpl, self.stack) estr = 'Property error : test_resource: Property Foo not assigned' - self.assertEqual(estr, res.create()) + self.assertRaises(exception.ResourceFailure, res.create) self.assertEqual(res.CREATE_FAILED, res.state) def test_create_fail_prop_typo(self): @@ -255,7 +255,7 @@ class ResourceTest(unittest.TestCase): res = generic_rsrc.GenericResource(rname, tmpl, self.stack) estr = 'Property error : test_resource: Property Foo not assigned' - self.assertEqual(estr, res.create()) + self.assertRaises(exception.ResourceFailure, res.create) self.assertEqual(res.CREATE_FAILED, res.state) def test_update_ok(self): diff --git a/heat/tests/test_user.py b/heat/tests/test_user.py index 52fc616364..a81ffbafab 100644 --- a/heat/tests/test_user.py +++ b/heat/tests/test_user.py @@ -329,8 +329,7 @@ class AccessKeyTest(unittest.TestCase): resource = user.AccessKey('HostKeys', t['Resources']['HostKeys'], stack) - self.assertEqual('could not find user test_stack.NoExist', - resource.create()) + self.assertRaises(exception.ResourceFailure, resource.create) self.assertEqual(user.AccessKey.CREATE_FAILED, resource.state) diff --git a/heat/tests/test_volume.py b/heat/tests/test_volume.py index 28c1fef3aa..079d1e93ae 100644 --- a/heat/tests/test_volume.py +++ b/heat/tests/test_volume.py @@ -22,6 +22,7 @@ import unittest from nose.plugins.attrib import attr from heat.common import context +from heat.common import exception from heat.common import template_format from heat.engine import parser from heat.engine.resources import volume as vol @@ -147,7 +148,7 @@ class VolumeTest(unittest.TestCase): resource = vol.Volume('DataVolume', t['Resources']['DataVolume'], stack) - self.assertEqual(resource.create(), 'error') + self.assertRaises(exception.ResourceFailure, resource.create) self.m.VerifyAll() @@ -184,7 +185,7 @@ class VolumeTest(unittest.TestCase): resource = vol.VolumeAttachment('MountPoint', t['Resources']['MountPoint'], stack) - self.assertEqual(resource.create(), 'error') + self.assertRaises(exception.ResourceFailure, resource.create) self.m.VerifyAll()