Merge "Defer exceptions in calculating node_data()"
This commit is contained in:
commit
0ec8fa8e43
@ -51,13 +51,20 @@ class NodeData(object):
|
||||
|
||||
def attributes(self):
|
||||
"""Return a dict of all available top-level attribute values."""
|
||||
return {k: v
|
||||
for k, v in self._attributes.items()
|
||||
if isinstance(k, six.string_types)}
|
||||
attrs = {k: v
|
||||
for k, v in self._attributes.items()
|
||||
if isinstance(k, six.string_types)}
|
||||
for v in six.itervalues(attrs):
|
||||
if isinstance(v, Exception):
|
||||
raise v
|
||||
return attrs
|
||||
|
||||
def attribute(self, attr_name):
|
||||
"""Return the specified attribute value."""
|
||||
return self._attributes[attr_name]
|
||||
val = self._attributes[attr_name]
|
||||
if isinstance(val, Exception):
|
||||
raise val
|
||||
return val
|
||||
|
||||
def attribute_names(self):
|
||||
"""Iterate over valid top-level attribute names."""
|
||||
@ -73,6 +80,10 @@ class NodeData(object):
|
||||
This is the format that is serialised and stored in the database's
|
||||
SyncPoints.
|
||||
"""
|
||||
for v in six.itervalues(self._attributes):
|
||||
if isinstance(v, Exception):
|
||||
raise v
|
||||
|
||||
return {
|
||||
'id': self.primary_key,
|
||||
'name': self.name,
|
||||
|
@ -1037,7 +1037,15 @@ class Resource(status.ResourceStatus):
|
||||
try:
|
||||
yield attr, self.FnGetAtt(*path)
|
||||
except exception.InvalidTemplateAttribute as ita:
|
||||
# Attribute doesn't exist, so don't store it. Whatever
|
||||
# tries to access it will get another
|
||||
# InvalidTemplateAttribute exception at that point
|
||||
LOG.info('%s', ita)
|
||||
except Exception as exc:
|
||||
# Store the exception that occurred. It will be
|
||||
# re-raised when something tries to access it, or when
|
||||
# we try to serialise the NodeData.
|
||||
yield attr, exc
|
||||
|
||||
load_all = not self.stack.in_convergence_check
|
||||
dep_attrs = self.referenced_attrs(stk_defn,
|
||||
|
@ -99,3 +99,57 @@ outputs:
|
||||
actual_output_value = self.client.stacks.output_show(
|
||||
stack_identifier, 'output_value')['output']
|
||||
self.assertEqual(expected_output_value, actual_output_value)
|
||||
|
||||
nested_template = '''
|
||||
heat_template_version: 2015-10-15
|
||||
resources:
|
||||
parent:
|
||||
type: 1.yaml
|
||||
outputs:
|
||||
resource_output_a:
|
||||
value: { get_attr: [parent, resource_output_a] }
|
||||
description: 'parent a'
|
||||
resource_output_b:
|
||||
value: { get_attr: [parent, resource_output_b] }
|
||||
description: 'parent b'
|
||||
'''
|
||||
error_template = '''
|
||||
heat_template_version: 2015-10-15
|
||||
resources:
|
||||
test_resource_a:
|
||||
type: OS::Heat::TestResource
|
||||
properties:
|
||||
value: 'a'
|
||||
test_resource_b:
|
||||
type: OS::Heat::TestResource
|
||||
properties:
|
||||
value: 'b'
|
||||
outputs:
|
||||
resource_output_a:
|
||||
description: 'Output of resource a'
|
||||
value: { get_attr: [test_resource_a, output] }
|
||||
resource_output_b:
|
||||
description: 'Output of resource b'
|
||||
value: { get_param: foo }
|
||||
'''
|
||||
|
||||
def test_output_error_nested(self):
|
||||
stack_identifier = self.stack_create(
|
||||
template=self.nested_template,
|
||||
files={'1.yaml': self.error_template}
|
||||
)
|
||||
self.update_stack(stack_identifier, template=self.nested_template,
|
||||
files={'1.yaml': self.error_template})
|
||||
expected_list = [{u'output_key': u'resource_output_a',
|
||||
u'output_value': u'a',
|
||||
u'description': u'parent a'},
|
||||
{u'output_key': u'resource_output_b',
|
||||
u'output_value': None,
|
||||
u'output_error': u'Error in parent output '
|
||||
u'resource_output_b: The Parameter'
|
||||
u' (foo) was not provided.',
|
||||
u'description': u'parent b'}]
|
||||
|
||||
actual_list = self.client.stacks.get(stack_identifier).outputs
|
||||
sorted_actual_list = sorted(actual_list, key=lambda x: x['output_key'])
|
||||
self.assertEqual(expected_list, sorted_actual_list)
|
||||
|
Loading…
Reference in New Issue
Block a user