From 8f2993610d0f12f7e711107eaf56db3d28b112b0 Mon Sep 17 00:00:00 2001 From: Steve Baker Date: Mon, 12 Nov 2012 08:38:38 +1300 Subject: [PATCH] Pass a Stack entity to Stack.load(). Every call to Stack.load (except one) is loading models.Stack then passing just the ID to Stack.load, which then loads models.Stack again. As far as I can tell, SQLAlchemy doesn't have a 2nd level cache, so this results in the db being queried twice. This change makes it possibe to pass a stack *or* an ID to Stack.load, and converts all calls to pass in a stack if it is available. Change-Id: I501ebd403a241cc3b4a5c1e3070137cfc360bbda --- heat/engine/api.py | 2 +- heat/engine/parser.py | 15 ++++++++------- heat/engine/service.py | 20 ++++++++++---------- heat/engine/watchrule.py | 2 +- heat/tests/test_api_cfn_v1.py | 12 ++++++------ heat/tests/test_api_openstack_v1.py | 12 ++++++------ heat/tests/test_engine_service.py | 18 +++++++++++------- 7 files changed, 43 insertions(+), 38 deletions(-) diff --git a/heat/engine/api.py b/heat/engine/api.py index 2c04db39..08795a97 100644 --- a/heat/engine/api.py +++ b/heat/engine/api.py @@ -164,7 +164,7 @@ EVENT_KEYS = ( def format_event(context, event): - stack = parser.Stack.load(context, event.stack.id) + stack = parser.Stack.load(context, stack=event.stack) result = { EVENT_ID: event.id, EVENT_STACK_ID: dict(stack.identifier()), diff --git a/heat/engine/parser.py b/heat/engine/parser.py index c0ea0008..eda5af99 100644 --- a/heat/engine/parser.py +++ b/heat/engine/parser.py @@ -95,17 +95,18 @@ class Stack(object): return deps @classmethod - def load(cls, context, stack_id, resolve_data=True): + def load(cls, context, stack_id=None, stack=None, resolve_data=True): '''Retrieve a Stack from the database''' - s = db_api.stack_get(context, stack_id) - if s is None: + if stack is None: + stack = db_api.stack_get(context, stack_id) + if stack is None: message = 'No stack exists with id "%s"' % str(stack_id) raise exception.NotFound(message) - template = Template.load(context, s.raw_template_id) - params = Parameters(s.name, template, s.parameters) - stack = cls(context, s.name, template, params, - stack_id, s.status, s.status_reason, s.timeout, + template = Template.load(context, stack.raw_template_id) + params = Parameters(stack.name, template, stack.parameters) + stack = cls(context, stack.name, template, params, + stack.id, stack.status, stack.status_reason, stack.timeout, resolve_data) return stack diff --git a/heat/engine/service.py b/heat/engine/service.py index b7d75460..07d9dbbb 100644 --- a/heat/engine/service.py +++ b/heat/engine/service.py @@ -69,7 +69,7 @@ class EngineService(service.Service): """ s = db_api.stack_get_by_name(context, stack_name) if s: - stack = parser.Stack.load(context, s.id) + stack = parser.Stack.load(context, stack=s) return dict(stack.identifier()) else: raise AttributeError('Unknown stack name') @@ -102,7 +102,7 @@ class EngineService(service.Service): stacks = [self._get_stack(context, stack_identity)] def format_stack_detail(s): - stack = parser.Stack.load(context, s.id) + stack = parser.Stack.load(context, stack=s) return api.format_stack(stack) return {'stacks': [format_stack_detail(s) for s in stacks]} @@ -115,7 +115,7 @@ class EngineService(service.Service): stacks = db_api.stack_get_by_tenant(context) or [] def format_stack_detail(s): - stack = parser.Stack.load(context, s.id, resolve_data=False) + stack = parser.Stack.load(context, stack=s, resolve_data=False) return api.format_stack(stack) return {'stacks': [format_stack_detail(s) for s in stacks]} @@ -173,7 +173,7 @@ class EngineService(service.Service): # Get the database representation of the existing stack db_stack = self._get_stack(context, stack_identity) - current_stack = parser.Stack.load(context, db_stack.id) + current_stack = parser.Stack.load(context, stack=db_stack) # Now parse the template and any parameters for the updated # stack definition. @@ -258,7 +258,7 @@ class EngineService(service.Service): logger.info('deleting stack %s' % st.name) - stack = parser.Stack.load(context, st.id) + stack = parser.Stack.load(context, stack=st) # TODO Angus do we need a kill or will stop do? if st.id in self.stg: @@ -314,7 +314,7 @@ class EngineService(service.Service): def describe_stack_resource(self, context, stack_identity, resource_name): s = self._get_stack(context, stack_identity) - stack = parser.Stack.load(context, s.id) + stack = parser.Stack.load(context, stack=s) if resource_name not in stack: raise AttributeError('Unknown resource name') @@ -339,7 +339,7 @@ class EngineService(service.Service): if not s: raise AttributeError("The specified stack doesn't exist") - stack = parser.Stack.load(context, s.id) + stack = parser.Stack.load(context, stack=s) if logical_resource_id is not None: name_match = lambda r: r.name == logical_resource_id @@ -353,7 +353,7 @@ class EngineService(service.Service): def list_stack_resources(self, context, stack_identity): s = self._get_stack(context, stack_identity) - stack = parser.Stack.load(context, s.id) + stack = parser.Stack.load(context, stack=s) return [api.format_stack_resource(resource) for resource in stack if resource.id is not None] @@ -385,7 +385,7 @@ class EngineService(service.Service): logger.warn("Stack %s not found" % stack_name) return ['stack', None] - stack = parser.Stack.load(None, s.id) + stack = parser.Stack.load(None, stack=s) if resource_name not in stack: logger.warn("Resource not found %s:%s." % (stack_name, resource_name)) @@ -404,7 +404,7 @@ class EngineService(service.Service): logger.warn("Stack %s not found" % stack_id) return ['stack', None] - stack = parser.Stack.load(None, s.id) + stack = parser.Stack.load(None, stack=s) if resource_name not in stack: logger.warn("Resource not found %s:%s." % (stack_id, resource_name)) diff --git a/heat/engine/watchrule.py b/heat/engine/watchrule.py index abc0a109..3091cf87 100644 --- a/heat/engine/watchrule.py +++ b/heat/engine/watchrule.py @@ -233,7 +233,7 @@ class WatchRule(object): parser.Stack.UPDATE_COMPLETE): user_creds = db_api.user_creds_get(s.user_creds_id) ctxt = ctxtlib.RequestContext.from_dict(user_creds) - stack = parser.Stack.load(ctxt, s.id) + stack = parser.Stack.load(ctxt, stack=s) for a in self.rule[self.ACTION_MAP[new_state]]: greenpool.spawn_n(stack[a].alarm) actioned = True diff --git a/heat/tests/test_api_cfn_v1.py b/heat/tests/test_api_cfn_v1.py index e56f231f..8ba73bbe 100644 --- a/heat/tests/test_api_cfn_v1.py +++ b/heat/tests/test_api_cfn_v1.py @@ -95,8 +95,8 @@ class StackControllerTest(unittest.TestCase): u'stack_name': u'wordpress', u'stack_status': u'CREATE_COMPLETE'}]} self.m.StubOutWithMock(rpc, 'call') - rpc.call(dummy_req.context, self.topic, {'method': 'show_stack', - 'args': {'stack_identity': None}, + rpc.call(dummy_req.context, self.topic, {'method': 'list_stacks', + 'args': {}, 'version': self.api_version}, None ).AndReturn(engine_resp) @@ -121,8 +121,8 @@ class StackControllerTest(unittest.TestCase): # Insert an engine RPC error and ensure we map correctly to the # heat exception type self.m.StubOutWithMock(rpc, 'call') - rpc.call(dummy_req.context, self.topic, {'method': 'show_stack', - 'args': {'stack_identity': None}, + rpc.call(dummy_req.context, self.topic, {'method': 'list_stacks', + 'args': {}, 'version': self.api_version}, None ).AndRaise(rpc_common.RemoteError("AttributeError")) @@ -140,8 +140,8 @@ class StackControllerTest(unittest.TestCase): # Insert an engine RPC error and ensure we map correctly to the # heat exception type self.m.StubOutWithMock(rpc, 'call') - rpc.call(dummy_req.context, self.topic, {'method': 'show_stack', - 'args': {'stack_identity': None}, + rpc.call(dummy_req.context, self.topic, {'method': 'list_stacks', + 'args': {}, 'version': self.api_version}, None ).AndRaise(rpc_common.RemoteError("Exception")) diff --git a/heat/tests/test_api_openstack_v1.py b/heat/tests/test_api_openstack_v1.py index c5b03878..667aab3a 100644 --- a/heat/tests/test_api_openstack_v1.py +++ b/heat/tests/test_api_openstack_v1.py @@ -235,8 +235,8 @@ class StackControllerTest(unittest.TestCase): } self.m.StubOutWithMock(rpc, 'call') rpc.call(req.context, self.topic, - {'method': 'show_stack', - 'args': {'stack_identity': None}, + {'method': 'list_stacks', + 'args': {}, 'version': self.api_version}, None).AndReturn(engine_resp) self.m.ReplayAll() @@ -266,8 +266,8 @@ class StackControllerTest(unittest.TestCase): self.m.StubOutWithMock(rpc, 'call') rpc.call(req.context, self.topic, - {'method': 'show_stack', - 'args': {'stack_identity': None}, + {'method': 'list_stacks', + 'args': {}, 'version': self.api_version}, None).AndRaise(rpc_common.RemoteError("AttributeError")) self.m.ReplayAll() @@ -282,8 +282,8 @@ class StackControllerTest(unittest.TestCase): self.m.StubOutWithMock(rpc, 'call') rpc.call(req.context, self.topic, - {'method': 'show_stack', - 'args': {'stack_identity': None}, + {'method': 'list_stacks', + 'args': {}, 'version': self.api_version}, None).AndRaise(rpc_common.RemoteError("Exception")) self.m.ReplayAll() diff --git a/heat/tests/test_engine_service.py b/heat/tests/test_engine_service.py index 056490c2..6647e284 100644 --- a/heat/tests/test_engine_service.py +++ b/heat/tests/test_engine_service.py @@ -215,13 +215,14 @@ class stackServiceCreateUpdateDeleteTest(unittest.TestCase): def test_stack_delete(self): stack_name = 'service_delete_test_stack' stack = get_wordpress_stack(stack_name, self.ctx) - stack.store() + sid = stack.store() + s = db_api.stack_get(self.ctx, sid) self.m.StubOutWithMock(parser.Stack, 'load') #self.m.StubOutWithMock(threadgroup, 'ThreadGroup') #threadgroup.ThreadGroup(stack_name).AndReturn(DummyThreadGroup()) - parser.Stack.load(self.ctx, stack.id).AndReturn(stack) + parser.Stack.load(self.ctx, stack=s).AndReturn(stack) self.m.ReplayAll() @@ -246,13 +247,14 @@ class stackServiceCreateUpdateDeleteTest(unittest.TestCase): template = '{ "Template": "data" }' old_stack = get_wordpress_stack(stack_name, self.ctx) - old_stack.store() + sid = old_stack.store() + s = db_api.stack_get(self.ctx, sid) stack = get_wordpress_stack(stack_name, self.ctx) self.m.StubOutWithMock(parser, 'Stack') self.m.StubOutWithMock(parser.Stack, 'load') - parser.Stack.load(self.ctx, old_stack.id).AndReturn(old_stack) + parser.Stack.load(self.ctx, stack=s).AndReturn(old_stack) self.m.StubOutWithMock(parser, 'Template') self.m.StubOutWithMock(parser, 'Parameters') @@ -283,12 +285,14 @@ class stackServiceCreateUpdateDeleteTest(unittest.TestCase): old_stack = get_wordpress_stack(stack_name, self.ctx) old_stack.store() + sid = old_stack.store() + s = db_api.stack_get(self.ctx, sid) stack = get_wordpress_stack(stack_name, self.ctx) self.m.StubOutWithMock(parser, 'Stack') self.m.StubOutWithMock(parser.Stack, 'load') - parser.Stack.load(self.ctx, old_stack.id).AndReturn(old_stack) + parser.Stack.load(self.ctx, stack=s).AndReturn(old_stack) self.m.StubOutWithMock(parser, 'Template') self.m.StubOutWithMock(parser, 'Parameters') @@ -426,7 +430,7 @@ class stackServiceTest(unittest.TestCase): self.assertTrue('event_time' in ev) def test_stack_describe_all(self): - sl = self.man.show_stack(self.ctx, None) + sl = self.man.list_stacks(self.ctx) self.assertEqual(len(sl['stacks']), 1) for s in sl['stacks']: @@ -438,7 +442,7 @@ class stackServiceTest(unittest.TestCase): self.tenant = 'stack_describe_all_empty_tenant' self.setUp() - sl = self.man.show_stack(self.ctx, None) + sl = self.man.list_stacks(self.ctx) self.assertEqual(len(sl['stacks']), 0) -- 2.45.2