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
This commit is contained in:
Zane Bitter 2017-05-18 23:10:30 -04:00
parent ee5dc7c120
commit 960f626c24
3 changed files with 30 additions and 24 deletions

View File

@ -45,10 +45,10 @@ from heat.engine import scheduler
from heat.engine import status from heat.engine import status
from heat.engine import support from heat.engine import support
from heat.engine import sync_point from heat.engine import sync_point
from heat.engine import template
from heat.objects import resource as resource_objects from heat.objects import resource as resource_objects
from heat.objects import resource_data as resource_data_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 resource_properties_data as rpd_objects
from heat.objects import stack as stack_objects
from heat.rpc import client as rpc_client from heat.rpc import client as rpc_client
cfg.CONF.import_opt('action_retry_limit', 'heat.common.config') cfg.CONF.import_opt('action_retry_limit', 'heat.common.config')
@ -322,36 +322,45 @@ class Resource(status.ResourceStatus):
@classmethod @classmethod
def load(cls, context, resource_id, current_traversal, is_update, data): 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 from heat.engine import stack as stack_mod
db_res = resource_objects.Resource.get_obj(context, resource_id) db_res = resource_objects.Resource.get_obj(context, resource_id)
curr_stack = stack_mod.Stack.load(context, stack_id=db_res.stack_id, curr_stack = stack_mod.Stack.load(context, stack_id=db_res.stack_id,
cache_data=data) 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 if (db_res.current_template_id != curr_stack.t.id and
(db_res.action != cls.INIT or (db_res.action != cls.INIT or
not is_update or not is_update or
current_traversal != curr_stack.current_traversal)): current_traversal != curr_stack.current_traversal)):
# load stack with template owning the resource # load the definition associated with the resource's template
db_stack = stack_objects.Stack.get_by_id(context, db_res.stack_id) current_template_id = db_res.current_template_id
db_stack.raw_template = None current_template = template.Template.load(context,
db_stack.raw_template_id = db_res.current_template_id current_template_id)
resource_owning_stack = stack_mod.Stack.load(context, initial_stk_defn = curr_stack.defn.clone_with_new_template(
stack=db_stack) current_template,
curr_stack.identifier())
curr_stack.defn = initial_stk_defn
# Load only the resource in question; don't load all resources # Load only the resource in question; don't load all resources
# by invoking stack.resources. Maintain light-weight stack. # by invoking stack.resources. Maintain light-weight stack.
res_defn = resource_owning_stack.defn.resource_definition(db_res.name) res_defn = initial_stk_defn.resource_definition(db_res.name)
resource = cls(db_res.name, res_defn, resource_owning_stack) resource = cls(db_res.name, res_defn, curr_stack)
resource._load_data(db_res) resource._load_data(db_res)
# assign current stack to the resource for updates curr_stack.defn = latest_stk_defn
if is_update: return resource, initial_stk_defn, curr_stack
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
def make_replacement(self, new_tmpl_id): def make_replacement(self, new_tmpl_id):
# 1. create the replacement with "replaces" = self.id # 1. create the replacement with "replaces" = self.id

View File

@ -94,11 +94,6 @@ class WaitCondition(heat_wc.HeatWaitCondition):
raise ValueError(_("WaitCondition invalid Handle %s") % raise ValueError(_("WaitCondition invalid Handle %s") %
handle_id.resource_name) 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): def handle_create(self):
self._validate_handle_url() self._validate_handle_url()
return super(WaitCondition, self).handle_create() return super(WaitCondition, self).handle_create()

View File

@ -170,8 +170,10 @@ class WorkerService(object):
in_data = sync_point.deserialize_input_data(data) in_data = sync_point.deserialize_input_data(data)
resource_data = node_data.load_resources_data(in_data if is_update resource_data = node_data.load_resources_data(in_data if is_update
else {}) else {})
rsrc, rsrc_owning_stack, stack = check_resource.load_resource( rsrc, stk_defn, stack = check_resource.load_resource(cnxt, resource_id,
cnxt, resource_id, resource_data, current_traversal, is_update) resource_data,
current_traversal,
is_update)
if rsrc is None: if rsrc is None:
return return