Optionally include attrs referenced in outputs in node data

Change-Id: I2838403a91708d9fe1a31f580f43f056de68f3da
Partially-Implements: blueprint stack-definition
This commit is contained in:
Zane Bitter 2017-07-19 17:35:39 -04:00
parent 119f3e4aa5
commit 959cc21363
2 changed files with 50 additions and 8 deletions

View File

@ -11,6 +11,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import collections
import contextlib
import datetime as dt
import pydoc
@ -954,7 +955,9 @@ class Resource(status.ResourceStatus):
This enables the resource to calculate which of its attributes will
be used. By default, attributes referenced in either other resources
or outputs will be included. Either can be excluded by setting the
`in_resources` or `in_outputs` parameters to False.
`in_resources` or `in_outputs` parameters to False. To limit to a
subset of outputs, pass an iterable of the output names to examine
for the `in_outputs` parameter.
"""
def get_dep_attrs(source_dict):
return set(self.stack.get_dep_attrs(six.itervalues(source_dict),
@ -963,8 +966,14 @@ class Resource(status.ResourceStatus):
refd_attrs = set()
if in_resources:
refd_attrs |= get_dep_attrs(self.stack.resources)
if in_outputs:
refd_attrs |= get_dep_attrs(self.stack.outputs)
subset_outputs = isinstance(in_outputs, collections.Iterable)
if subset_outputs or in_outputs:
if subset_outputs:
outputs = {k: self.stack.outputs[k] for k in in_outputs}
else:
outputs = self.stack.outputs
refd_attrs |= get_dep_attrs(outputs)
if attributes.ALL_ATTRIBUTES in refd_attrs:
refd_attrs.remove(attributes.ALL_ATTRIBUTES)
@ -972,15 +981,20 @@ class Resource(status.ResourceStatus):
return refd_attrs
def node_data(self):
def node_data(self, for_resources=True, for_outputs=False):
"""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.
By default, those attribute values that are referenced by other
resources are included. These can be ignored by setting the
for_resources parameter to False. If the for_outputs parameter is
True, those attribute values that are referenced by stack outputs are
included. If the for_outputs parameter is an iterable of output names,
only those attribute values referenced by the specified stack outputs
are included.
After calling this method, the resource's attribute cache is
populated with any cacheable attribute values referenced by stack
@ -1005,10 +1019,11 @@ class Resource(status.ResourceStatus):
except exception.InvalidTemplateAttribute as ita:
LOG.info('%s', ita)
dep_attrs = self.referenced_attrs(in_outputs=False)
dep_attrs = self.referenced_attrs(in_resources=for_resources,
in_outputs=for_outputs)
# Ensure all attributes referenced in outputs get cached
if self.stack.convergence:
if for_outputs is False and self.stack.convergence:
out_attrs = self.referenced_attrs(in_resources=False)
for e in get_attrs(out_attrs - dep_attrs, cacheable_only=True):
pass

View File

@ -145,6 +145,8 @@ outputs:
value: [{get_attr: [AResource, flat_dict, key2]},
{get_attr: [AResource, nested_dict, string]},
{get_attr: [BResource, attr_B3]}]
out2:
value: {get_resource: BResource}
"""
tmpl7 = """
@ -259,6 +261,31 @@ class ReferencedAttrsTest(common.HeatTestCase):
in_outputs=True),
{'attr_B3'})
def test_referenced_attrs_single_output(self):
self.assertEqual(self.resA.referenced_attrs(in_resources=False,
in_outputs={'out1'}),
{('flat_dict', 'key2'), ('nested_dict', 'string')})
self.assertEqual(self.resB.referenced_attrs(in_resources=False,
in_outputs={'out1'}),
{'attr_B3'})
self.assertEqual(self.resA.referenced_attrs(in_resources=False,
in_outputs={'out2'}),
set())
self.assertEqual(self.resB.referenced_attrs(in_resources=False,
in_outputs={'out2'}),
set())
def test_referenced_attrs_outputs_list(self):
self.assertEqual(self.resA.referenced_attrs(in_resources=False,
in_outputs={'out1',
'out2'}),
{('flat_dict', 'key2'), ('nested_dict', 'string')})
self.assertEqual(self.resB.referenced_attrs(in_resources=False,
in_outputs={'out1',
'out2'}),
{'attr_B3'})
def test_referenced_attrs_both(self):
self.assertEqual(self.resA.referenced_attrs(in_resources=True,
in_outputs=True),