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
@ -902,6 +902,15 @@ class Resource(object):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
return True
|
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,
|
def update_convergence(self, template_id, resource_data, engine_id,
|
||||||
timeout, new_stack):
|
timeout, new_stack):
|
||||||
"""Update the resource synchronously.
|
"""Update the resource synchronously.
|
||||||
@ -919,12 +928,16 @@ class Resource(object):
|
|||||||
)
|
)
|
||||||
|
|
||||||
with self.lock(engine_id):
|
with self.lock(engine_id):
|
||||||
|
registry = new_stack.env.registry
|
||||||
new_res_def = new_stack.t.resource_definitions(
|
new_res_def = new_stack.t.resource_definitions(
|
||||||
new_stack)[self.name]
|
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)
|
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:
|
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
|
action_rollback = self.stack.action == self.stack.ROLLBACK
|
||||||
status_in_progress = self.stack.status == self.stack.IN_PROGRESS
|
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):
|
def create_resource(self):
|
||||||
self.stack = parser.Stack(utils.dummy_context(), 'test_stack',
|
self.stack = parser.Stack(utils.dummy_context(), 'test_stack',
|
||||||
@ -3538,6 +3539,17 @@ class ResourceUpdateRestrictionTest(common.HeatTestCase):
|
|||||||
scheduler.TaskRunner(res.create)()
|
scheduler.TaskRunner(res.create)()
|
||||||
return res
|
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):
|
def test_update_restricted(self):
|
||||||
self.env_snippet = {u'resource_registry': {
|
self.env_snippet = {u'resource_registry': {
|
||||||
u'resources': {
|
u'resources': {
|
||||||
@ -3632,3 +3644,59 @@ class ResourceUpdateRestrictionTest(common.HeatTestCase):
|
|||||||
self.assertIn('requires replacement', six.text_type(error))
|
self.assertIn('requires replacement', six.text_type(error))
|
||||||
self.assertEqual(1, prep_replace.call_count)
|
self.assertEqual(1, prep_replace.call_count)
|
||||||
ev.assert_not_called()
|
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…
Reference in New Issue
Block a user