From 33b09448c14468b768d2d4da4f756e8132065d81 Mon Sep 17 00:00:00 2001 From: Zane Bitter Date: Mon, 5 Nov 2012 17:30:57 +0100 Subject: [PATCH] Get rid of Resource.calculate_properties() Use the new Properties class to lazily load property values so that we always get the latest data, and get rid of the stateful hacks. Change-Id: I02a1b927606da217d4adab1ca04b659abadda2ce Signed-off-by: Zane Bitter --- heat/engine/checkeddict.py | 37 ++++++------------------- heat/engine/parser.py | 9 ------ heat/engine/resources/autoscaling.py | 3 -- heat/engine/resources/instance.py | 1 - heat/engine/resources/resource.py | 20 ++++--------- heat/engine/resources/user.py | 1 - heat/engine/resources/wait_condition.py | 1 - heat/tests/test_engine_service.py | 1 - heat/tests/test_loadbalancer.py | 2 +- heat/tests/test_quantum.py | 14 +++++----- heat/tests/unit/test_checkeddict.py | 4 ++- 11 files changed, 24 insertions(+), 69 deletions(-) diff --git a/heat/engine/checkeddict.py b/heat/engine/checkeddict.py index daef6586..f2b3b14c 100644 --- a/heat/engine/checkeddict.py +++ b/heat/engine/checkeddict.py @@ -95,8 +95,10 @@ class CheckedDict(collections.MutableMapping): raise ValueError('%s: %s Value must be a map' % (self.name, key)) if 'Schema' in self.data[key]: - cdict = Properties(key, self.data[key]['Schema']) - cdict.data = self.data[key]['Schema'] + cdict = CheckedDict(key) + schema = self.data[key]['Schema'] + for n, s in schema.items(): + cdict.addschema(n, s) for k, v in value.items(): cdict[k] = v @@ -106,7 +108,10 @@ class CheckedDict(collections.MutableMapping): (self.name, key, value)) if 'Schema' in self.data[key]: for item in value: - cdict = Properties(key, self.data[key]['Schema']) + cdict = CheckedDict(key) + schema = self.data[key]['Schema'] + for n, s in schema.items(): + cdict.addschema(n, s) for k, v in item.items(): cdict[k] = v @@ -152,29 +157,3 @@ class CheckedDict(collections.MutableMapping): def __delitem__(self, k): del self.data[k] - - -class Properties(CheckedDict): - def __init__(self, name, schema): - CheckedDict.__init__(self, name) - self.data = deepcopy(schema) - - # set some defaults - for s in self.data: - if not 'Implemented' in self.data[s]: - self.data[s]['Implemented'] = True - if not 'Required' in self.data[s]: - self.data[s]['Required'] = False - - def validate(self): - for key in self.data: - # are there missing required Properties - if 'Required' in self.data[key]: - if self.data[key]['Required'] \ - and not 'Value' in self.data[key]: - return '%s Property must be provided' % key - - # are there unimplemented Properties - if not self.data[key]['Implemented'] and 'Value' in self.data[key]: - return '%s Property not implemented yet' % key - return None diff --git a/heat/engine/parser.py b/heat/engine/parser.py index ecde0ea5..2fc045d7 100644 --- a/heat/engine/parser.py +++ b/heat/engine/parser.py @@ -264,9 +264,6 @@ class Stack(object): failures = [] with eventlet.Timeout(self.timeout_mins * 60) as tmo: try: - for res in self: - res.calculate_properties() - # First delete any resources which are not in newstack for res in reversed(self): if not res.name in newstack.keys(): @@ -366,9 +363,6 @@ class Stack(object): ''' self.state_set(self.DELETE_IN_PROGRESS, 'Stack deletion started') - for res in self: - res.calculate_properties() - failures = [] for res in reversed(self): result = res.destroy() @@ -399,9 +393,6 @@ class Stack(object): deps = self.dependencies[self[resource_name]] failed = False - for res in self: - res.calculate_properties() - for res in reversed(deps): try: res.destroy() diff --git a/heat/engine/resources/autoscaling.py b/heat/engine/resources/autoscaling.py index 774a02f3..a5161a88 100644 --- a/heat/engine/resources/autoscaling.py +++ b/heat/engine/resources/autoscaling.py @@ -77,8 +77,6 @@ class AutoScalingGroup(resource.Resource): inst.destroy() def adjust(self, adjustment, adjustment_type='ChangeInCapacity'): - self.calculate_properties() - inst_list = [] if self.instance_id is not None: inst_list = sorted(self.instance_id.split(',')) @@ -190,7 +188,6 @@ class ScalingPolicy(resource.Resource): super(ScalingPolicy, self).__init__(name, json_snippet, stack) def alarm(self): - self.calculate_properties() group = self.stack.resources[self.properties['AutoScalingGroupName']] logger.info('%s Alarm, adjusting Group %s by %s' % diff --git a/heat/engine/resources/instance.py b/heat/engine/resources/instance.py index 076d6814..c6697a86 100644 --- a/heat/engine/resources/instance.py +++ b/heat/engine/resources/instance.py @@ -47,7 +47,6 @@ class Restarter(resource.Resource): return None def alarm(self): - self.calculate_properties() victim = self._find_resource(self.properties['InstanceId']) if victim is None: diff --git a/heat/engine/resources/resource.py b/heat/engine/resources/resource.py index 28681ced..186f5880 100644 --- a/heat/engine/resources/resource.py +++ b/heat/engine/resources/resource.py @@ -37,8 +37,8 @@ except ImportError: from heat.common import exception from heat.common import config from heat.db import api as db_api -from heat.engine import checkeddict from heat.engine import timestamp +from heat.engine.resources.properties import Properties from heat.openstack.common import log as logging from heat.openstack.common import cfg @@ -114,7 +114,10 @@ class Resource(object): self.context = stack.context self.name = name self.t = stack.resolve_static_data(json_snippet) - self.properties = checkeddict.Properties(name, self.properties_schema) + self.properties = Properties(self.properties_schema, + self.t.get('Properties', {}), + self.stack.resolve_runtime_data, + self.name) resource = db_api.resource_get_by_name_and_stack(self.context, name, stack.id) @@ -321,10 +324,6 @@ class Resource(object): return self._quantum - def calculate_properties(self): - for p, v in self.parsed_template('Properties').items(): - self.properties[p] = v - def create(self): ''' Create the resource. Subclasses should provide a handle_create() method @@ -336,7 +335,6 @@ class Resource(object): logger.info('creating %s' % str(self)) try: - self.calculate_properties() self.properties.validate() self.state_set(self.CREATE_IN_PROGRESS) if callable(getattr(self, 'handle_create', None)): @@ -365,9 +363,6 @@ class Resource(object): try: self.state_set(self.UPDATE_IN_PROGRESS) self.t = self.stack.resolve_static_data(json_snippet) - self.properties = checkeddict.Properties(self.name, - self.properties_schema) - self.calculate_properties() self.properties.validate() if callable(getattr(self, 'handle_update', None)): result = self.handle_update() @@ -394,10 +389,6 @@ class Resource(object): def validate(self): logger.info('Validating %s' % str(self)) - try: - self.calculate_properties() - except ValueError as ex: - return str(ex) return self.properties.validate() def delete(self): @@ -476,7 +467,6 @@ class Resource(object): def _add_event(self, new_state, reason): '''Add a state change event to the database''' - self.calculate_properties() ev = {'logical_resource_id': self.name, 'physical_resource_id': self.instance_id, 'stack_id': self.stack.id, diff --git a/heat/engine/resources/user.py b/heat/engine/resources/user.py index 40b8e796..16a6ac10 100644 --- a/heat/engine/resources/user.py +++ b/heat/engine/resources/user.py @@ -199,7 +199,6 @@ class AccessKey(resource.Resource): def FnGetAtt(self, key): res = None log_res = None - self.calculate_properties() if key == 'UserName': res = self.properties['UserName'] log_res = res diff --git a/heat/engine/resources/wait_condition.py b/heat/engine/resources/wait_condition.py index 20073ddc..74d5c7dc 100644 --- a/heat/engine/resources/wait_condition.py +++ b/heat/engine/resources/wait_condition.py @@ -86,7 +86,6 @@ class WaitCondition(resource.Resource): def _get_handle_resource_id(self): if self.resource_id is None: - self.calculate_properties() handle_url = self.properties['Handle'] self.resource_id = handle_url.split('/')[-1] return self.resource_id diff --git a/heat/tests/test_engine_service.py b/heat/tests/test_engine_service.py index c19970a5..9dde9684 100644 --- a/heat/tests/test_engine_service.py +++ b/heat/tests/test_engine_service.py @@ -70,7 +70,6 @@ def setup_mocks(mocks, stack): instances.Instance.nova().MultipleTimes().AndReturn(fc) instance = stack.resources['WebServer'] - instance.calculate_properties() server_userdata = instance._build_userdata(instance.properties['UserData']) mocks.StubOutWithMock(fc.servers, 'create') fc.servers.create(image=744, flavor=3, key_name='test', diff --git a/heat/tests/test_loadbalancer.py b/heat/tests/test_loadbalancer.py index 4c2c22aa..5f8f12fb 100644 --- a/heat/tests/test_loadbalancer.py +++ b/heat/tests/test_loadbalancer.py @@ -105,7 +105,7 @@ class LoadBalancerTest(unittest.TestCase): 'UnhealthyThreshold': '5', 'Interval': '30', 'Timeout': '5'} - resource.properties['HealthCheck'] = hc + resource.t['Properties']['HealthCheck'] = hc self.assertEqual(None, resource.validate()) hc['Timeout'] = 35 diff --git a/heat/tests/test_quantum.py b/heat/tests/test_quantum.py index 9091cca6..40776b03 100644 --- a/heat/tests/test_quantum.py +++ b/heat/tests/test_quantum.py @@ -24,7 +24,7 @@ import json from nose.plugins.attrib import attr from heat.common import exception -from heat.engine import checkeddict +from heat.engine.resources import properties from heat.engine.resources.quantum import net from heat.engine.resources.quantum.quantum import QuantumResource as qr from heat.engine import parser @@ -104,12 +104,12 @@ class QuantumTest(unittest.TestCase): return resource def test_validate_properties(self): - p = checkeddict.Properties('foo', net.Net.properties_schema) vs = {'router:external': True} - p.update({ + data = { 'admin_state_up': False, 'value_specs': vs - }) + } + p = properties.Properties(net.Net.properties_schema, data) self.assertEqual(None, qr.validate_properties(p)) vs['shared'] = True @@ -131,11 +131,11 @@ class QuantumTest(unittest.TestCase): self.assertEqual(None, qr.validate_properties(p)) def test_prepare_properties(self): - p = checkeddict.Properties('foo', net.Net.properties_schema) - p.update({ + data = { 'admin_state_up': False, 'value_specs': {'router:external': True} - }) + } + p = properties.Properties(net.Net.properties_schema, data) props = qr.prepare_properties(p, 'resource_name') self.assertEqual({ 'name': 'resource_name', diff --git a/heat/tests/unit/test_checkeddict.py b/heat/tests/unit/test_checkeddict.py index a00fbd3e..e1ec6a44 100644 --- a/heat/tests/unit/test_checkeddict.py +++ b/heat/tests/unit/test_checkeddict.py @@ -110,7 +110,9 @@ class CheckedDictTest(unittest.TestCase): 'Schema': listeners_schema} } - cd = checkeddict.Properties('nested', properties_schema) + cd = checkeddict.CheckedDict('nested') + for p, s in properties_schema.items(): + cd.addschema(p, s) hc = {'HealthyThreshold': 'bla', 'Interval': '45'} self.assertRaises(ValueError, cd.__setitem__, 'HealthCheck', hc) -- 2.45.2