summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--heat/engine/api.py13
-rw-r--r--heat/engine/parser.py3
-rw-r--r--heat/rpc/api.py2
-rw-r--r--heat/tests/test_engine_api_utils.py34
-rw-r--r--heat/tests/test_parser.py3
5 files changed, 50 insertions, 5 deletions
diff --git a/heat/engine/api.py b/heat/engine/api.py
index d0df38984..382c36f77 100644
--- a/heat/engine/api.py
+++ b/heat/engine/api.py
@@ -68,10 +68,15 @@ def format_stack_outputs(stack, outputs):
that matches the API output expectations.
'''
def format_stack_output(k):
- return {api.OUTPUT_DESCRIPTION: outputs[k].get('Description',
- 'No description given'),
- api.OUTPUT_KEY: k,
- api.OUTPUT_VALUE: stack.output(k)}
+ output = {
+ api.OUTPUT_DESCRIPTION: outputs[k].get('Description',
+ 'No description given'),
+ api.OUTPUT_KEY: k,
+ api.OUTPUT_VALUE: stack.output(k)
+ }
+ if outputs[k].get('error_msg'):
+ output.update({api.OUTPUT_ERROR: outputs[k].get('error_msg')})
+ return output
return [format_stack_output(key) for key in outputs]
diff --git a/heat/engine/parser.py b/heat/engine/parser.py
index b863c60b9..d1e66e920 100644
--- a/heat/engine/parser.py
+++ b/heat/engine/parser.py
@@ -800,7 +800,8 @@ class Stack(collections.Mapping):
value = self.outputs[key].get('Value', '')
try:
return function.resolve(value)
- except Exception:
+ except Exception as ex:
+ self.outputs[key]['error_msg'] = six.text_type(ex)
return None
def restart_resource(self, resource_name):
diff --git a/heat/rpc/api.py b/heat/rpc/api.py
index 95e63e6c1..1b5495829 100644
--- a/heat/rpc/api.py
+++ b/heat/rpc/api.py
@@ -42,9 +42,11 @@ STACK_KEYS = (
STACK_OUTPUT_KEYS = (
OUTPUT_DESCRIPTION,
OUTPUT_KEY, OUTPUT_VALUE,
+ OUTPUT_ERROR,
) = (
'description',
'output_key', 'output_value',
+ 'output_error',
)
RES_KEYS = (
diff --git a/heat/tests/test_engine_api_utils.py b/heat/tests/test_engine_api_utils.py
index 772c95aa2..fdb2e6077 100644
--- a/heat/tests/test_engine_api_utils.py
+++ b/heat/tests/test_engine_api_utils.py
@@ -216,6 +216,40 @@ class FormatTest(HeatTestCase):
info = api.format_stack(self.stack)
self.assertEqual('foobar', info[rpc_api.STACK_OUTPUTS])
+ def test_format_stack_outputs(self):
+ template = parser.Template({
+ 'HeatTemplateFormatVersion': '2012-12-12',
+ 'Resources': {
+ 'generic': {'Type': 'GenericResourceType'}
+ },
+ 'Outputs': {
+ 'correct_output': {
+ 'Description': 'Good output',
+ 'Value': {'Fn::GetAtt': ['generic', 'Foo']}
+ },
+ 'incorrect_output': {
+ 'Value': {'Fn::GetAtt': ['generic', 'Bar']}
+ }
+ }
+ })
+ stack = parser.Stack(utils.dummy_context(), 'test_stack',
+ template, stack_id=str(uuid.uuid4()))
+ stack.action = 'CREATE'
+ stack.status = 'COMPLETE'
+ stack['generic'].action = 'CREATE'
+ stack['generic'].status = 'COMPLETE'
+ info = api.format_stack_outputs(stack, stack.outputs)
+ expected = [{'description': 'No description given',
+ 'output_error': 'The Referenced Attribute (generic Bar) '
+ 'is incorrect.',
+ 'output_key': 'incorrect_output',
+ 'output_value': None},
+ {'description': 'Good output',
+ 'output_key': 'correct_output',
+ 'output_value': 'generic'}]
+
+ self.assertEqual(expected, info)
+
class FormatValidateParameterTest(HeatTestCase):
diff --git a/heat/tests/test_parser.py b/heat/tests/test_parser.py
index 123e0c34c..e7820b704 100644
--- a/heat/tests/test_parser.py
+++ b/heat/tests/test_parser.py
@@ -3089,6 +3089,9 @@ class StackTest(HeatTestCase):
self.stack.state)
self.assertIsNone(self.stack.output('Resource_attr'))
+ self.assertEqual('The Referenced Attribute (AResource Bar) is '
+ 'incorrect.',
+ self.stack.outputs['Resource_attr']['error_msg'])
self.stack.delete()