From 960f626c2455b77e654aea1d79597fadb91dc894 Mon Sep 17 00:00:00 2001 From: Zane Bitter Date: Thu, 18 May 2017 23:10:30 -0400 Subject: [PATCH] Avoid creating two Stacks when loading Resource When load()ing a Resource in order to check it, we must load its definition from whatever version of the template it was created or last updated with. Previously we created a second Stack object with that template in order to obtain the resource definition. Since all we really need in order to obtain this is the StackDefinition, create just that instead. Change-Id: Ia05983c3d1b838d2e28bb5eca38d13e83ccaf368 Implements: blueprint stack-definition --- heat/engine/resource.py | 43 +++++++++++-------- .../resources/aws/cfn/wait_condition.py | 5 --- heat/engine/worker.py | 6 ++- 3 files changed, 30 insertions(+), 24 deletions(-) diff --git a/heat/engine/resource.py b/heat/engine/resource.py index a53c9f28f1..2951e5cce2 100644 --- a/heat/engine/resource.py +++ b/heat/engine/resource.py @@ -45,10 +45,10 @@ from heat.engine import scheduler from heat.engine import status from heat.engine import support from heat.engine import sync_point +from heat.engine import template from heat.objects import resource as resource_objects from heat.objects import resource_data as resource_data_objects from heat.objects import resource_properties_data as rpd_objects -from heat.objects import stack as stack_objects from heat.rpc import client as rpc_client cfg.CONF.import_opt('action_retry_limit', 'heat.common.config') @@ -322,36 +322,45 @@ class Resource(status.ResourceStatus): @classmethod def load(cls, context, resource_id, current_traversal, is_update, data): + """Load a specified resource from the database to check. + + Returns a tuple of the Resource, the StackDefinition corresponding to + the resource's ResourceDefinition (i.e. the one the resource was last + updated to if it has already been created, or the one it will be + created with if it hasn't been already), and the Stack containing the + latest StackDefinition (i.e. the one that the latest traversal is + updating to. + + The latter two must remain in-scope, because the Resource holds weak + references to them. + """ from heat.engine import stack as stack_mod db_res = resource_objects.Resource.get_obj(context, resource_id) curr_stack = stack_mod.Stack.load(context, stack_id=db_res.stack_id, cache_data=data) - resource_owning_stack = curr_stack + initial_stk_defn = latest_stk_defn = curr_stack.defn if (db_res.current_template_id != curr_stack.t.id and (db_res.action != cls.INIT or not is_update or current_traversal != curr_stack.current_traversal)): - # load stack with template owning the resource - db_stack = stack_objects.Stack.get_by_id(context, db_res.stack_id) - db_stack.raw_template = None - db_stack.raw_template_id = db_res.current_template_id - resource_owning_stack = stack_mod.Stack.load(context, - stack=db_stack) + # load the definition associated with the resource's template + current_template_id = db_res.current_template_id + current_template = template.Template.load(context, + current_template_id) + initial_stk_defn = curr_stack.defn.clone_with_new_template( + current_template, + curr_stack.identifier()) + curr_stack.defn = initial_stk_defn # Load only the resource in question; don't load all resources # by invoking stack.resources. Maintain light-weight stack. - res_defn = resource_owning_stack.defn.resource_definition(db_res.name) - resource = cls(db_res.name, res_defn, resource_owning_stack) + res_defn = initial_stk_defn.resource_definition(db_res.name) + resource = cls(db_res.name, res_defn, curr_stack) resource._load_data(db_res) - # assign current stack to the resource for updates - if is_update: - resource.stack = curr_stack - - # return resource owning stack so that it is not GCed since it - # is the only stack instance with a weak-ref from resource - return resource, resource_owning_stack, curr_stack + curr_stack.defn = latest_stk_defn + return resource, initial_stk_defn, curr_stack def make_replacement(self, new_tmpl_id): # 1. create the replacement with "replaces" = self.id diff --git a/heat/engine/resources/aws/cfn/wait_condition.py b/heat/engine/resources/aws/cfn/wait_condition.py index 669ffd75f4..b4fde054bb 100644 --- a/heat/engine/resources/aws/cfn/wait_condition.py +++ b/heat/engine/resources/aws/cfn/wait_condition.py @@ -94,11 +94,6 @@ class WaitCondition(heat_wc.HeatWaitCondition): raise ValueError(_("WaitCondition invalid Handle %s") % handle_id.resource_name) - def _get_handle_resource(self): - handle_url = self.properties[self.HANDLE] - handle_id = identifier.ResourceIdentifier.from_arn_url(handle_url) - return self.stack[handle_id.resource_name] - def handle_create(self): self._validate_handle_url() return super(WaitCondition, self).handle_create() diff --git a/heat/engine/worker.py b/heat/engine/worker.py index 2987deb1bf..7cf58acb0b 100644 --- a/heat/engine/worker.py +++ b/heat/engine/worker.py @@ -170,8 +170,10 @@ class WorkerService(object): in_data = sync_point.deserialize_input_data(data) resource_data = node_data.load_resources_data(in_data if is_update else {}) - rsrc, rsrc_owning_stack, stack = check_resource.load_resource( - cnxt, resource_id, resource_data, current_traversal, is_update) + rsrc, stk_defn, stack = check_resource.load_resource(cnxt, resource_id, + resource_data, + current_traversal, + is_update) if rsrc is None: return