Merge "Convergence replace restriction for type change"

This commit is contained in:
Jenkins 2016-02-24 23:42:55 +00:00 committed by Gerrit Code Review
commit 815f36d78d
2 changed files with 83 additions and 2 deletions

View File

@ -921,6 +921,15 @@ class Resource(object):
except ValueError:
return True
def _check_for_convergence_replace(self, restricted_actions):
if 'replace' in restricted_actions:
ex = exception.ResourceActionRestricted(action='replace')
failure = exception.ResourceFailure(ex, self, self.UPDATE)
self._add_event(self.UPDATE, self.FAILED, six.text_type(ex))
raise failure
else:
raise exception.UpdateReplace(self.name)
def update_convergence(self, template_id, resource_data, engine_id,
timeout, new_stack):
"""Update the resource synchronously.
@ -938,12 +947,16 @@ class Resource(object):
)
with self.lock(engine_id):
registry = new_stack.env.registry
new_res_def = new_stack.t.resource_definitions(
new_stack)[self.name]
new_res_type = new_stack.env.registry.get_class_to_instantiate(
new_res_type = registry.get_class_to_instantiate(
new_res_def.resource_type, resource_name=self.name)
restricted_actions = registry.get_rsrc_restricted_actions(
self.name)
if type(self) is not new_res_type:
raise exception.UpdateReplace(self.name)
self._check_for_convergence_replace(restricted_actions)
action_rollback = self.stack.action == self.stack.ROLLBACK
status_in_progress = self.stack.status == self.stack.IN_PROGRESS

View File

@ -3576,6 +3576,7 @@ class ResourceUpdateRestrictionTest(common.HeatTestCase):
}
}
}
self.dummy_timeout = 10
def create_resource(self):
self.stack = parser.Stack(utils.dummy_context(), 'test_stack',
@ -3585,6 +3586,17 @@ class ResourceUpdateRestrictionTest(common.HeatTestCase):
scheduler.TaskRunner(res.create)()
return res
def create_convergence_resource(self):
self.stack = parser.Stack(utils.dummy_context(), 'test_stack',
template.Template(self.tmpl, env=self.env),
stack_id=str(uuid.uuid4()))
res_data = {}
res = self.stack['bar']
self.patchobject(res, 'lock')
scheduler.TaskRunner(res.create_convergence, self.stack.t.id,
res_data, 'engine-007', self.dummy_timeout)()
return res
def test_update_restricted(self):
self.env_snippet = {u'resource_registry': {
u'resources': {
@ -3679,3 +3691,59 @@ class ResourceUpdateRestrictionTest(common.HeatTestCase):
self.assertIn('requires replacement', six.text_type(error))
self.assertEqual(1, prep_replace.call_count)
ev.assert_not_called()
def test_replace_restricted_type_change_with_convergence(self):
self.env_snippet = {u'resource_registry': {
u'resources': {
'bar': {'restricted_actions': 'replace'}
}
}
}
self.env = environment.Environment()
self.env.load(self.env_snippet)
res = self.create_convergence_resource()
ev = self.patchobject(res, '_add_event')
bar = self.tmpl['resources']['bar']
bar['type'] = 'OS::Heat::None'
self.new_stack = parser.Stack(utils.dummy_context(), 'test_stack',
template.Template(self.tmpl,
env=self.env))
error = self.assertRaises(exception.ResourceFailure,
scheduler.TaskRunner(res.update_convergence,
self.stack.t.id,
{},
'engine-007',
self.dummy_timeout,
self.new_stack))
self.assertEqual('ResourceActionRestricted: resources.bar: '
'replace is restricted for resource.',
six.text_type(error))
self.assertEqual((res.CREATE, res.COMPLETE), res.state)
ev.assert_called_with(res.UPDATE, res.FAILED,
'replace is restricted for resource.')
def test_update_restricted_type_change_with_convergence(self):
self.env_snippet = {u'resource_registry': {
u'resources': {
'bar': {'restricted_actions': 'update'}
}
}
}
self.env = environment.Environment()
self.env.load(self.env_snippet)
res = self.create_convergence_resource()
ev = self.patchobject(res, '_add_event')
bar = self.tmpl['resources']['bar']
bar['type'] = 'OS::Heat::None'
self.new_stack = parser.Stack(utils.dummy_context(), 'test_stack',
template.Template(self.tmpl,
env=self.env))
error = self.assertRaises(exception.UpdateReplace,
scheduler.TaskRunner(res.update_convergence,
self.stack.t.id,
{},
'engine-007',
self.dummy_timeout,
self.new_stack))
self.assertIn('requires replacement', six.text_type(error))
ev.assert_not_called()