Always cache attributes in outputs in Resource.node_data()

Ensure that attributes that are referenced in outputs get cached (and
therefore stored in the database) even when they are not referenced by
other resources.

Change-Id: I667ab04f91edddef5c5dbec0a89d465110c312b4
Closes-Bug: #1660831
This commit is contained in:
Zane Bitter 2017-07-10 13:47:59 -04:00
parent b902d93ade
commit cfff39ce68
4 changed files with 36 additions and 5 deletions

View File

@ -943,15 +943,39 @@ class Resource(status.ResourceStatus):
return refd_attrs
def node_data(self):
def get_attrs(attrs):
"""Return a NodeData object representing the resource.
The NodeData object returned contains basic data about the resource,
including its name, ID and state, as well as its reference ID and any
attribute values that are used.
Only those attribute values that are referenced by other
resources are included.
After calling this method, the resource's attribute cache is
populated with any cacheable attribute values referenced by stack
outputs, even if they are not also referenced by other resources.
"""
def get_attrs(attrs, cacheable_only=False):
for attr in attrs:
path = (attr,) if isinstance(attr, six.string_types) else attr
if (cacheable_only and
(self.attributes.get_cache_mode(path[0]) ==
attributes.Schema.CACHE_NONE)):
continue
try:
yield attr, self._get_attribute_caching(*path)
except exception.InvalidTemplateAttribute as ita:
LOG.info('%s', ita)
dep_attrs = self.referenced_attrs(in_outputs=False)
# Ensure all attributes referenced in outputs get cached
if self.stack.convergence:
out_attrs = self.referenced_attrs(in_resources=False)
for e in get_attrs(out_attrs - dep_attrs, cacheable_only=True):
pass
return node_data.NodeData(self.id, self.name, self.uuid,
self.get_reference_id(),
dict(get_attrs(dep_attrs)),

View File

@ -530,9 +530,6 @@ class EngineService(service.ServiceBase):
stack, resolve_outputs=resolve_outputs) for stack in stacks]
if resolve_outputs:
# Cases where stored attributes may not exist for a resource:
# * For those resources that have attributes that were
# *not* referenced by other resources, their attributes
# are not resolved/stored over a stack update traversal
# * The resource is an AutoScalingGroup that received a signal
# * Near simultaneous updates (say by an update and a signal)
# * The first time resolving a pre-Pike stack

View File

@ -2781,7 +2781,7 @@ class StackGetAttributesTestConvergence(common.HeatTestCase):
self.stack.t.parse(self.stack, self.snippet),
self.resource_name)
with mock.patch.object(rsrc.stack, 'get_dep_attrs') as mock_da:
mock_da.return_value = dep_attrs
mock_da.return_value = list(dep_attrs)
rsrc_data = rsrc.node_data()
# store as cache data
self.stack.cache_data = {

View File

@ -0,0 +1,10 @@
---
features:
- Resource attributes are now stored at the time a resource is created or
updated, allowing for fast resolution of outputs without having to retrieve
live data from the underlying physical resource. To minimise compatibility
problems, the behaviour of the `show` attribute, the `with_attr` option to
the resource show API, and stacks that do not yet use the convergence
architecture (due to the convergence_engine being disabled at the time they
were created) is unchanged - in each of these cases live data will still be
returned.