Merge "Catch exceptions for restore_prev_rsrc/prepare_for_replace"

This commit is contained in:
Jenkins 2015-11-10 05:23:23 +00:00 committed by Gerrit Code Review
commit 5ffbb4759f
2 changed files with 55 additions and 36 deletions

View File

@ -931,7 +931,6 @@ class Resource(object):
if not self._needs_update(after, before, after_props, before_props, if not self._needs_update(after, before, after_props, before_props,
prev_resource): prev_resource):
return return
if not cfg.CONF.convergence_engine: if not cfg.CONF.convergence_engine:
if (self.action, self.status) in ( if (self.action, self.status) in (
(self.CREATE, self.IN_PROGRESS), (self.CREATE, self.IN_PROGRESS),
@ -958,6 +957,7 @@ class Resource(object):
self._update_stored_properties() self._update_stored_properties()
except exception.UpdateReplace as ex: except exception.UpdateReplace as ex:
# catch all UpdateReplace expections # catch all UpdateReplace expections
try:
if (self.stack.action == 'ROLLBACK' and if (self.stack.action == 'ROLLBACK' and
self.stack.status == 'IN_PROGRESS' and self.stack.status == 'IN_PROGRESS' and
not cfg.CONF.convergence_engine): not cfg.CONF.convergence_engine):
@ -966,6 +966,12 @@ class Resource(object):
self.restore_prev_rsrc() self.restore_prev_rsrc()
else: else:
self.prepare_for_replace() self.prepare_for_replace()
except Exception as e:
# if any exception happen, we should set the resource to
# FAILED, then raise ResourceFailure
failure = exception.ResourceFailure(e, self, action)
self.state_set(action, self.FAILED, six.text_type(failure))
raise failure
raise ex raise ex
def prepare_for_replace(self): def prepare_for_replace(self):

View File

@ -363,63 +363,76 @@ class ResourceTest(common.HeatTestCase):
self.assertIsNotNone(res.updated_time) self.assertIsNotNone(res.updated_time)
self.assertNotEqual(res.updated_time, stored_time) self.assertNotEqual(res.updated_time, stored_time)
def test_update_replace(self): def _setup_resource_for_update(self, res_name):
class TestResource(resource.Resource): class TestResource(resource.Resource):
properties_schema = {'a_string': {'Type': 'String'}} properties_schema = {'a_string': {'Type': 'String'}}
update_allowed_properties = ('a_string',) update_allowed_properties = ('a_string',)
resource._register_class('TestResource', TestResource) resource._register_class('TestResource', TestResource)
tmpl = rsrc_defn.ResourceDefinition('test_resource', tmpl = rsrc_defn.ResourceDefinition(res_name,
'TestResource') 'TestResource')
res = TestResource('test_resource', tmpl, self.stack) res = TestResource('test_resource', tmpl, self.stack)
utmpl = rsrc_defn.ResourceDefinition(res_name, 'TestResource',
{'a_string': 'foo'})
return res, utmpl
def test_update_replace(self):
res, utmpl = self._setup_resource_for_update(
res_name='test_update_replace')
res.prepare_for_replace = mock.Mock() res.prepare_for_replace = mock.Mock()
utmpl = rsrc_defn.ResourceDefinition('test_resource', 'TestResource',
{'a_string': 'foo'})
self.assertRaises( self.assertRaises(
exception.UpdateReplace, scheduler.TaskRunner(res.update, utmpl)) exception.UpdateReplace, scheduler.TaskRunner(res.update, utmpl))
self.assertTrue(res.prepare_for_replace.called) self.assertTrue(res.prepare_for_replace.called)
def test_update_replace_prepare_replace_error(self):
# test if any error happened when prepare_for_replace,
# whether the resource will go to FAILED
res, utmpl = self._setup_resource_for_update(
res_name='test_update_replace_prepare_replace_error')
res.prepare_for_replace = mock.Mock(side_effect=Exception)
self.assertRaises(
exception.ResourceFailure,
scheduler.TaskRunner(res.update, utmpl))
self.assertTrue(res.prepare_for_replace.called)
self.assertEqual((res.UPDATE, res.FAILED), res.state)
def test_update_rsrc_in_progress_raises_exception(self): def test_update_rsrc_in_progress_raises_exception(self):
class TestResource(resource.Resource): res, utmpl = self._setup_resource_for_update(
properties_schema = {'a_string': {'Type': 'String'}} res_name='test_update_rsrc_in_progress_raises_exception')
update_allowed_properties = ('a_string',)
cfg.CONF.set_override('convergence_engine', False) cfg.CONF.set_override('convergence_engine', False)
resource._register_class('TestResource', TestResource)
tmpl = rsrc_defn.ResourceDefinition('test_resource',
'TestResource')
res = TestResource('test_resource', tmpl, self.stack)
utmpl = rsrc_defn.ResourceDefinition('test_resource', 'TestResource',
{'a_string': 'foo'})
res.action = res.UPDATE res.action = res.UPDATE
res.status = res.IN_PROGRESS res.status = res.IN_PROGRESS
self.assertRaises( self.assertRaises(
exception.ResourceFailure, scheduler.TaskRunner(res.update, utmpl)) exception.ResourceFailure, scheduler.TaskRunner(res.update, utmpl))
def test_update_replace_rollback(self): def test_update_replace_rollback(self):
class TestResource(resource.Resource): res, utmpl = self._setup_resource_for_update(
properties_schema = {'a_string': {'Type': 'String'}} res_name='test_update_replace_rollback')
update_allowed_properties = ('a_string',)
resource._register_class('TestResource', TestResource)
tmpl = rsrc_defn.ResourceDefinition('test_resource',
'TestResource')
self.stack.state_set('ROLLBACK', 'IN_PROGRESS', 'Simulate rollback')
res = TestResource('test_resource', tmpl, self.stack)
res.restore_prev_rsrc = mock.Mock() res.restore_prev_rsrc = mock.Mock()
self.stack.state_set('ROLLBACK', 'IN_PROGRESS', 'Simulate rollback')
utmpl = rsrc_defn.ResourceDefinition('test_resource', 'TestResource',
{'a_string': 'foo'})
self.assertRaises( self.assertRaises(
exception.UpdateReplace, scheduler.TaskRunner(res.update, utmpl)) exception.UpdateReplace, scheduler.TaskRunner(res.update, utmpl))
self.assertTrue(res.restore_prev_rsrc.called) self.assertTrue(res.restore_prev_rsrc.called)
def test_update_replace_rollback_restore_prev_rsrc_error(self):
res, utmpl = self._setup_resource_for_update(
res_name='restore_prev_rsrc_error')
res.restore_prev_rsrc = mock.Mock(side_effect=Exception)
self.stack.state_set('ROLLBACK', 'IN_PROGRESS', 'Simulate rollback')
self.assertRaises(
exception.ResourceFailure, scheduler.TaskRunner(res.update, utmpl))
self.assertTrue(res.restore_prev_rsrc.called)
self.assertEqual((res.UPDATE, res.FAILED), res.state)
def test_update_replace_in_failed_without_nested(self): def test_update_replace_in_failed_without_nested(self):
tmpl = rsrc_defn.ResourceDefinition('test_resource', tmpl = rsrc_defn.ResourceDefinition('test_resource',
'GenericResourceType', 'GenericResourceType',