Make sure that the properties are stored on updates

Previously properties_data was only stored on creation, now
this is getting passed to the update mechanism too.
Later we can look at reworking this into a single mechanism.

Closes-bug: #1377681
Change-Id: If3d476f34b9e61a3c99f63ba33734a875353c8fc
This commit is contained in:
Angus Salkeld 2014-10-10 12:00:37 +10:00
parent dab36df3db
commit d32370233e
5 changed files with 97 additions and 7 deletions

View File

@ -903,12 +903,14 @@ class Resource(object):
if self.id is not None:
try:
rs = db_api.resource_get(self.context, self.id)
rs.update_and_save({'action': self.action,
'status': self.status,
'status_reason': reason,
'stack_id': self.stack.id,
'updated_at': self.updated_time,
'nova_instance': self.resource_id})
rs.update_and_save({
'action': self.action,
'status': self.status,
'status_reason': reason,
'stack_id': self.stack.id,
'updated_at': self.updated_time,
'properties_data': self._stored_properties_data,
'nova_instance': self.resource_id})
except Exception as ex:
LOG.error(_('DB error %s') % ex)

View File

@ -60,11 +60,13 @@ class ResWithComplexPropsAndAttrs(GenericResource):
properties_schema = {'a_string': {'Type': 'String'},
'a_list': {'Type': 'List'},
'a_map': {'Type': 'Map'}}
'a_map': {'Type': 'Map'},
'an_int': {'Type': 'Integer'}}
attributes_schema = {'list': attributes.Schema('A list'),
'map': attributes.Schema('A map'),
'string': attributes.Schema('A string')}
update_allowed_properties = ('an_int',)
def _resolve_attribute(self, name):
try:

View File

@ -122,6 +122,7 @@ class AutoScalingTest(HeatTestCase):
self.m.StubOutWithMock(neutronclient.Client, 'show_pool')
self.m.StubOutWithMock(neutronclient.Client, 'show_vip')
self.m.StubOutWithMock(neutronclient.Client, 'create_member')
self.m.StubOutWithMock(neutronclient.Client, 'delete_member')
self.m.StubOutWithMock(neutronclient.Client, 'list_members')
self.m.StubOutWithMock(nova.NovaClientPlugin, 'server_to_ipaddress')
@ -309,6 +310,8 @@ class AutoScalingTest(HeatTestCase):
nova.NovaClientPlugin.server_to_ipaddress(
mox.IgnoreArg()).AndReturn('1.2.3.5')
neutronclient.Client.delete_member(mox.IgnoreArg()).AndReturn(None)
neutronclient.Client.create_member(memberb_block).\
AndReturn(memberb_ret_block)
@ -318,6 +321,12 @@ class AutoScalingTest(HeatTestCase):
neutronclient.Client.create_member(memberc_block).\
AndReturn(memberc_ret_block)
nova.NovaClientPlugin.server_to_ipaddress(
mox.IgnoreArg()).AndReturn('1.2.3.4')
neutronclient.Client.create_member(membera_block).\
AndReturn(membera_ret_block)
self.m.ReplayAll()
# Start of stack create

View File

@ -924,6 +924,8 @@ class StackTest(HeatTestCase):
generic_rsrc.ResourceWithProps)
resource._register_class('ResourceWithComplexAttributesType',
generic_rsrc.ResourceWithComplexAttributes)
resource._register_class('ResWithComplexPropsAndAttrs',
generic_rsrc.ResWithComplexPropsAndAttrs)
def test_stack_reads_tenant(self):
stack = parser.Stack(self.ctx, 'test_stack', self.tmpl,
@ -2180,6 +2182,69 @@ class StackTest(HeatTestCase):
self.m.VerifyAll()
def test_update_modify_ok_replace_int(self):
# create
#========
tmpl = {'heat_template_version': '2013-05-23',
'resources': {'AResource': {
'type': 'ResWithComplexPropsAndAttrs',
'properties': {'an_int': 1}}}}
self.stack = parser.Stack(self.ctx, 'update_test_stack',
template.Template(tmpl))
self.stack.store()
stack_id = self.stack.id
self.stack.create()
self.assertEqual((parser.Stack.CREATE, parser.Stack.COMPLETE),
self.stack.state)
value1 = 2
prop_diff1 = {'an_int': value1}
value2 = 1
prop_diff2 = {'an_int': value2}
self.m.StubOutWithMock(generic_rsrc.ResWithComplexPropsAndAttrs,
'handle_update')
generic_rsrc.ResWithComplexPropsAndAttrs.handle_update(
IgnoreArg(), IgnoreArg(), prop_diff1)
generic_rsrc.ResWithComplexPropsAndAttrs.handle_update(
IgnoreArg(), IgnoreArg(), prop_diff2)
self.m.ReplayAll()
# update 1
#==========
self.stack = parser.Stack.load(self.ctx, stack_id=stack_id)
tmpl2 = {'heat_template_version': '2013-05-23',
'resources': {'AResource': {
'type': 'ResWithComplexPropsAndAttrs',
'properties': {'an_int': value1}}}}
updated_stack = parser.Stack(self.ctx, 'updated_stack',
template.Template(tmpl2))
self.stack.update(updated_stack)
self.assertEqual((parser.Stack.UPDATE, parser.Stack.COMPLETE),
self.stack.state)
# update 2
#==========
# reload the previous stack
self.stack = parser.Stack.load(self.ctx, stack_id=stack_id)
tmpl3 = {'heat_template_version': '2013-05-23',
'resources': {'AResource': {
'type': 'ResWithComplexPropsAndAttrs',
'properties': {'an_int': value2}}}}
updated_stack = parser.Stack(self.ctx, 'updated_stack',
template.Template(tmpl3))
self.stack.update(updated_stack)
self.assertEqual((parser.Stack.UPDATE, parser.Stack.COMPLETE),
self.stack.state)
self.m.VerifyAll()
def test_update_modify_param_ok_replace(self):
tmpl = {
'HeatTemplateFormatVersion': '2012-12-12',

View File

@ -1485,6 +1485,18 @@ class PropertiesTest(testtools.TestCase):
self.assertEqual(expected,
dict((n, dict(s)) for n, s in props_schemata.items()))
def test_compare_same(self):
schema = {'foo': {'Type': 'Integer'}}
props_a = properties.Properties(schema, {'foo': 1})
props_b = properties.Properties(schema, {'foo': 1})
self.assertFalse(props_a != props_b)
def test_compare_different(self):
schema = {'foo': {'Type': 'Integer'}}
props_a = properties.Properties(schema, {'foo': 0})
props_b = properties.Properties(schema, {'foo': 1})
self.assertTrue(props_a != props_b)
class PropertiesValidationTest(testtools.TestCase):
def test_required(self):