Convergence replace restriction for type change
This implements replace restrictions when resource type changes with convergence enabled. Change-Id: If7a2c7712335bbeaf7acbd257288fb44e02d88ff Blueprint: stack-update-restrict
This commit is contained in:
parent
536c8580a0
commit
8c55606cfb
heat
@ -902,6 +902,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.
|
||||
@ -919,12 +928,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
|
||||
|
@ -3529,6 +3529,7 @@ class ResourceUpdateRestrictionTest(common.HeatTestCase):
|
||||
}
|
||||
}
|
||||
}
|
||||
self.dummy_timeout = 10
|
||||
|
||||
def create_resource(self):
|
||||
self.stack = parser.Stack(utils.dummy_context(), 'test_stack',
|
||||
@ -3538,6 +3539,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': {
|
||||
@ -3632,3 +3644,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()
|
||||
|
Loading…
x
Reference in New Issue
Block a user