Merge "Convergence resource operations"

This commit is contained in:
Jenkins 2015-06-11 04:07:56 +00:00 committed by Gerrit Code Review
commit 8b15f476c5
4 changed files with 151 additions and 23 deletions

View File

@ -294,13 +294,6 @@ class Resource(object):
rs.update_and_save({'rsrc_metadata': metadata})
self._rsrc_metadata = metadata
def clear_requirers(self, gone_requires):
self.requires = set(self.requires) - set(gone_requires)
self.requires = list(self.requires)
self._store_or_update(self.action,
self.status,
self.status_reason)
@classmethod
def set_needed_by(cls, db_rsrc, needed_by):
if db_rsrc:
@ -619,6 +612,25 @@ class Resource(object):
'''
return self
def create_convergence(self, template_id, resource_data):
'''
Creates the resource by invoking the scheduler TaskRunner
and it persists the resource's current_template_id to template_id and
resource's requires to list of the required resource id from the
given resource_data.
'''
runner = scheduler.TaskRunner(self.create)
runner()
# update the resource db record
self.current_template_id = template_id
self.requires = (list({graph_key[0]
for graph_key, data in resource_data.items()}))
self._store_or_update(self.action,
self.status,
self.status_reason)
@scheduler.wrappertask
def create(self):
'''
@ -759,6 +771,32 @@ class Resource(object):
except ValueError:
return True
def update_convergence(self, template_id, resource_data):
'''
Updates the resource by invoking the scheduler TaskRunner
and it persists the resource's current_template_id to template_id and
resource's requires to list of the required resource id from the
given resource_data and existing resource's requires.
'''
if self.status == self.IN_PROGRESS:
ex = UpdateInProgress(self.name)
LOG.exception(ex)
raise ex
# update the resource
runner = scheduler.TaskRunner(self.update, self.t)
runner()
# update the resource db record
self.current_template_id = template_id
current_requires = {graph_key[0]
for graph_key, data in resource_data.items()}
self.requires = (list(set(self.requires) | current_requires))
self._store_or_update(self.action,
self.status,
self.status_reason)
@scheduler.wrappertask
def update(self, after, before=None, prev_resource=None):
'''
@ -949,6 +987,31 @@ class Resource(object):
msg = _('"%s" deletion policy not supported') % policy
raise exception.StackValidationFailed(message=msg)
def delete_convergence(self, template_id, resource_data):
'''
Deletes the resource by invoking the scheduler TaskRunner
and it persists the resource's current_template_id to template_id and
resource's requires to list of the required resource id from the
given resource_data and existing resource's requires.
'''
if self.status == self.IN_PROGRESS:
ex = UpdateInProgress(self.name)
LOG.exception(ex)
raise ex
# delete the resource
runner = scheduler.TaskRunner(self.delete)
runner()
# update the resource db record
self.current_template_id = template_id
current_requires = {graph_key[0]
for graph_key, data in resource_data.items()}
self.requires = (list(set(self.requires) - current_requires))
self._store_or_update(self.action,
self.status,
self.status_reason)
@scheduler.wrappertask
def delete(self):
'''

View File

@ -210,18 +210,15 @@ def check_resource_update(rsrc, template_id, data):
input_data = {in_data.name: in_data for in_data in data.values()}
if rsrc.resource_id is None:
rsrc.create(template_id, input_data)
rsrc.create_convergence(template_id, input_data)
else:
rsrc.update(template_id, input_data)
rsrc.update_convergence(template_id, input_data)
def check_resource_cleanup(rsrc, template_id, data):
'''
Delete the Resource if appropriate.
'''
# Clear out deleted resources from the requirers list
rsrc.clear_requirers(rsrc_id for rsrc_id, id in data.items()
if id is None)
if rsrc.current_template_id != template_id:
rsrc.delete(template_id, data)
rsrc.delete_convergence(template_id, data)

View File

@ -277,32 +277,28 @@ class MiscMethodsTest(common.HeatTestCase):
mock.ANY, {}, True)
self.assertTrue(mock_sync.called)
@mock.patch.object(resource.Resource, 'create')
@mock.patch.object(resource.Resource, 'create_convergence')
def test_check_resource_update_create(self, mock_create):
worker.check_resource_update(self.resource, self.resource.stack.t.id,
{})
self.assertTrue(mock_create.called)
@mock.patch.object(resource.Resource, 'update')
@mock.patch.object(resource.Resource, 'update_convergence')
def test_check_resource_update_update(self, mock_update):
self.resource.resource_id = 'physical-res-id'
worker.check_resource_update(self.resource, self.resource.stack.t.id,
{})
self.assertTrue(mock_update.called)
@mock.patch.object(resource.Resource, 'delete')
@mock.patch.object(resource.Resource, 'clear_requirers')
def test_check_resource_cleanup_delete(self, mock_cr, mock_delete):
@mock.patch.object(resource.Resource, 'delete_convergence')
def test_check_resource_cleanup_delete(self, mock_delete):
self.resource.current_template_id = 'new-template-id'
worker.check_resource_cleanup(self.resource, self.resource.stack.t.id,
{})
self.assertTrue(mock_cr.called)
self.assertTrue(mock_delete.called)
@mock.patch.object(resource.Resource, 'delete')
@mock.patch.object(resource.Resource, 'clear_requirers')
def test_check_resource_cleanup_nodelete(self, mock_cr, mock_delete):
@mock.patch.object(resource.Resource, 'delete_convergence')
def test_check_resource_cleanup_nodelete(self, mock_delete):
worker.check_resource_cleanup(self.resource, self.resource.stack.t.id,
{})
self.assertTrue(mock_cr.called)
self.assertFalse(mock_delete.called)

View File

@ -1393,6 +1393,78 @@ class ResourceTest(common.HeatTestCase):
res_obj = res_objs['test_res_enc']
self.assertEqual('string', res_obj.properties_data['prop1'])
@mock.patch.object(resource.Resource, '_store_or_update')
@mock.patch.object(resource.Resource, 'create')
def test_create_convergence(self,
mock_create,
mock_store_update_method):
tmpl = rsrc_defn.ResourceDefinition('test_res', 'Foo')
res = generic_rsrc.GenericResource('test_res', tmpl, self.stack)
res.create_convergence('template_key', {(1, True): {},
(1, True): {}})
mock_create.assert_called_once_with()
self.assertEqual('template_key', res.current_template_id)
self.assertEqual([1], res.requires)
self.assertTrue(mock_store_update_method.called)
@mock.patch.object(resource.Resource, '_store_or_update')
@mock.patch.object(resource.Resource, 'update')
def test_update_convergence(self,
mock_update,
mock_store_update_method
):
tmpl = rsrc_defn.ResourceDefinition('test_res', 'Foo')
res = generic_rsrc.GenericResource('test_res', tmpl, self.stack)
res.requires = [2]
res.update_convergence('template_key', {(1, True): {},
(1, True): {}})
mock_update.assert_called_once_with(res.t)
self.assertEqual('template_key', res.current_template_id)
self.assertEqual([1, 2], res.requires)
self.assertTrue(mock_store_update_method.called)
def test_update_in_progress_convergence(self):
tmpl = rsrc_defn.ResourceDefinition('test_res', 'Foo')
res = generic_rsrc.GenericResource('test_res', tmpl, self.stack)
res.status = resource.Resource.IN_PROGRESS
ex = self.assertRaises(resource.UpdateInProgress,
res.update_convergence,
'template_key',
{})
msg = ("The resource %s is already being updated." %
res.name)
self.assertEqual(msg, six.text_type(ex))
@mock.patch.object(resource.Resource, '_store_or_update')
@mock.patch.object(resource.Resource, 'delete')
def test_delete_convergence(self,
mock_delete,
mock_store_update_method):
tmpl = rsrc_defn.ResourceDefinition('test_res', 'Foo')
res = generic_rsrc.GenericResource('test_res', tmpl, self.stack)
res.requires = [1, 2]
res.delete_convergence('template_key', {(1, True): {},
(1, True): {}})
mock_delete.assert_called_once_with()
self.assertEqual('template_key', res.current_template_id)
self.assertEqual([2], res.requires)
self.assertTrue(mock_store_update_method.called)
def test_delete_in_progress_convergence(self):
tmpl = rsrc_defn.ResourceDefinition('test_res', 'Foo')
res = generic_rsrc.GenericResource('test_res', tmpl, self.stack)
res.status = resource.Resource.IN_PROGRESS
ex = self.assertRaises(resource.UpdateInProgress,
res.delete_convergence,
'template_key',
{})
msg = ("The resource %s is already being updated." %
res.name)
self.assertEqual(msg, six.text_type(ex))
class ResourceAdoptTest(common.HeatTestCase):
def setUp(self):