Pass on outputs errors to parent stacks

If getting an output from a child stack fails with an error, we didn't pass
on the error message to the parent stack that was requesting it but instead
reported essentially that the given output did not exist.

Change-Id: I5653baf310a29dc4829ad570c769cf67ce12695e
Partial-Bug: #1599114
(cherry picked from commit b90991e00b)
This commit is contained in:
Zane Bitter 2017-02-20 15:12:49 -05:00
parent 33c5eee231
commit e5cd344025
3 changed files with 20 additions and 8 deletions

View File

@ -154,6 +154,10 @@ class InvalidTemplateReference(HeatException):
' is incorrect.')
class TemplateOutputError(HeatException):
msg_fmt = _('Error in %(resource)s output %(attribute)s: %(message)s')
class InvalidExternalResourceDependency(HeatException):
msg_fmt = _("Invalid dependency with external %(resource_type)s "
"resource: %(external_id)s")

View File

@ -587,8 +587,10 @@ class StackResource(resource.Resource):
particular exception, not KeyError, being raised if the key does not
exist.)
"""
if self._outputs is None or self._outputs.get(op,
NotImplemented) is None:
if (self._outputs is None or
(op in self._outputs and
rpc_api.OUTPUT_ERROR not in self._outputs[op] and
self._outputs[op].get(rpc_api.OUTPUT_VALUE) is None)):
stack_identity = self.nested_identifier()
if stack_identity is None:
return
@ -597,14 +599,20 @@ class StackResource(resource.Resource):
if not stack:
return
outputs = stack[0].get(rpc_api.STACK_OUTPUTS) or {}
self._outputs = {o[rpc_api.OUTPUT_KEY]: o[rpc_api.OUTPUT_VALUE]
for o in outputs if rpc_api.OUTPUT_ERROR not in o}
self._outputs = {o[rpc_api.OUTPUT_KEY]: o for o in outputs}
try:
return self._outputs[op]
except KeyError:
if op not in self._outputs:
raise exception.InvalidTemplateAttribute(resource=self.name,
key=op)
output_data = self._outputs[op]
if rpc_api.OUTPUT_ERROR in output_data:
raise exception.TemplateOutputError(
resource=self.name,
attribute=op,
message=output_data[rpc_api.OUTPUT_ERROR])
return output_data[rpc_api.OUTPUT_VALUE]
def _resolve_attribute(self, name):
return self.get_output(name)

View File

@ -319,7 +319,7 @@ class ProviderTemplateTest(common.HeatTestCase):
output = {'outputs': [{'output_key': 'Foo', 'output_value': None,
'output_error': 'it is all bad'}]}
temp_res._rpc_client.show_stack.return_value = [output]
self.assertRaises(exception.InvalidTemplateAttribute,
self.assertRaises(exception.TemplateOutputError,
temp_res.FnGetAtt, 'Foo')
def test_properties_normal(self):