Produce more meaningful exception messages in nested stacks

This produces a nested exception like:
 'ValueError: resources.nested.resources.my_server: it is broken, sorry'

This re-uses the path mechanism that StackValidationFailed exception
uses.

Change-Id: Id5204c15ee96784e04522ab3c5a8e66900f9a1d3
Closes-bug: 1459837
diff --git a/common/test_resources/test_resource.py b/common/test_resources/test_resource.py
index 88f1745..55255a6 100644
--- a/common/test_resources/test_resource.py
+++ b/common/test_resources/test_resource.py
@@ -100,7 +100,7 @@
 
         # emulate failure
         if fail_prop:
-            raise Exception("Test Resource failed %s", self.name)
+            raise ValueError("Test Resource failed %s" % self.name)
 
     def handle_update(self, json_snippet=None, tmpl_diff=None, prop_diff=None):
         value = prop_diff.get(self.VALUE)
diff --git a/functional/test_template_resource.py b/functional/test_template_resource.py
index 5b189ac..0d5734b 100644
--- a/functional/test_template_resource.py
+++ b/functional/test_template_resource.py
@@ -648,3 +648,39 @@
 
         self.client.actions.check(stack_id=stack_identifier)
         self._wait_for_stack_status(stack_identifier, 'CHECK_COMPLETE')
+
+
+class TemplateResourceErrorMessageTest(test.HeatIntegrationTest):
+    """Prove that nested stack errors don't suck."""
+    template = '''
+HeatTemplateFormatVersion: '2012-12-12'
+Resources:
+  victim:
+    Type: fail.yaml
+'''
+    nested_templ = '''
+HeatTemplateFormatVersion: '2012-12-12'
+Resources:
+  oops:
+    Type: OS::Heat::TestResource
+    Properties:
+      fail: true
+      wait_secs: 2
+'''
+
+    def setUp(self):
+        super(TemplateResourceErrorMessageTest, self).setUp()
+        self.client = self.orchestration_client
+
+    def test_fail(self):
+        stack_identifier = self.stack_create(
+            template=self.template,
+            files={'fail.yaml': self.nested_templ},
+            expected_status='CREATE_FAILED')
+        stack = self.client.stacks.get(stack_identifier)
+
+        exp_path = 'resources.victim.resources.oops'
+        exp_msg = 'Test Resource failed oops'
+        exp = 'Resource CREATE failed: ValueError: %s: %s' % (exp_path,
+                                                              exp_msg)
+        self.assertEqual(exp, stack.stack_status_reason)