]> review.fuel-infra Code Review - openstack-build/heat-build.git/commitdiff
Tolerate bad environment until validation
authorSteven Hardy <shardy@redhat.com>
Thu, 19 Sep 2013 21:31:16 +0000 (22:31 +0100)
committerSteven Hardy <shardy@redhat.com>
Fri, 20 Sep 2013 08:37:05 +0000 (09:37 +0100)
Currently if we get a bad environment for a template_resource,
it causes an exception in the resource constructor, which does cause
the stack create to fail, but also all subsequent operations too.

By tolerating the error in the constructor, we can catch it instead at
validation time.

Change-Id: Ia971d8f1c50ca6f265ec36ea564aeba1638de541
Closes-Bug: 1227816

heat/engine/resources/template_resource.py
heat/tests/test_provider_template.py

index 50bb37f73be2ee187a3335d104efc7fed3c59768..0a5cf7ecaffbefc810cbd9b2cd3322f699854d8d 100644 (file)
@@ -50,7 +50,14 @@ class TemplateResource(stack_resource.StackResource):
         else:
             self.allowed_schemes = ('http', 'https', 'file')
 
-        tmpl = template.Template(self.parsed_nested)
+        # parse_nested can fail if the URL in the environment is bad
+        # or otherwise inaccessible.  Suppress the error here so the
+        # stack can be deleted, and detect it at validate/create time
+        try:
+            tmpl = template.Template(self.parsed_nested)
+        except ValueError:
+            tmpl = template.Template({})
+
         self.properties_schema = (properties.Properties
             .schema_from_params(tmpl.param_schemata()))
         self.attributes_schema = (attributes.Attributes
@@ -146,6 +153,11 @@ class TemplateResource(stack_resource.StackResource):
                 raise exception.StackValidationFailed(message=msg)
 
     def validate(self):
+        try:
+            td = self.template_data
+        except ValueError as ex:
+            msg = _("Failed to retrieve template data: %s") % str(ex)
+            raise exception.StackValidationFailed(message=msg)
         cri = self.stack.env.get_resource_info(
             self.type(),
             registry_type=environment.ClassResourceInfo)
index 828f2f0804959266f7e9bd9ceeace5d4d47c9ce7..08c96af793dd08e5ab9ecff6077dbb4a93fde8d8 100644 (file)
@@ -425,7 +425,7 @@ class ProviderTemplateTest(HeatTestCase):
 
     def test_user_template_not_retrieved_by_file(self):
         # make sure that a TemplateResource defined in the user environment
-        # can NOT be retrieved using the "file:" scheme.
+        # can NOT be retrieved using the "file:" scheme, validation should fail
         env = environment.Environment()
         test_templ_name = 'file:///etc/heatr/flippy.yaml'
         env.load({'resource_registry':
@@ -434,8 +434,64 @@ class ProviderTemplateTest(HeatTestCase):
                              parser.Template({}), env=env,
                              stack_id=uuidutils.generate_uuid())
 
-        self.assertRaises(ValueError,
-                          template_resource.TemplateResource,
-                          'test_t_res',
-                          {"Type": 'Test::Flippy'},
-                          stack)
+        temp_res = template_resource.TemplateResource('test_t_res',
+                                                      {"Type": 'Test::Flippy'},
+                                                      stack)
+
+        self.assertRaises(exception.StackValidationFailed, temp_res.validate)
+
+    def test_system_template_retrieve_fail(self):
+        # make sure that a TemplateResource defined in the global environment
+        # fails gracefully if the template file specified is inaccessible
+        # we should be able to create the TemplateResource object, but
+        # validation should fail, when the second attempt to access it is
+        # made in validate()
+        g_env = resources.global_env()
+        test_templ_name = 'file:///etc/heatr/frodo.yaml'
+        g_env.load({'resource_registry':
+                   {'Test::Frodo': test_templ_name}})
+        stack = parser.Stack(utils.dummy_context(), 'test_stack',
+                             parser.Template({}),
+                             stack_id=uuidutils.generate_uuid())
+
+        self.m.StubOutWithMock(urlfetch, "get")
+        urlfetch.get(test_templ_name,
+                     allowed_schemes=('http', 'https',
+                                      'file')).AndRaise(IOError)
+        urlfetch.get(test_templ_name,
+                     allowed_schemes=('http', 'https',
+                                      'file')).AndRaise(IOError)
+        self.m.ReplayAll()
+
+        temp_res = template_resource.TemplateResource('test_t_res',
+                                                      {"Type": 'Test::Frodo'},
+                                                      stack)
+        self.assertRaises(exception.StackValidationFailed, temp_res.validate)
+        self.m.VerifyAll()
+
+    def test_user_template_retrieve_fail(self):
+        # make sure that a TemplateResource defined in the user environment
+        # fails gracefully if the template file specified is inaccessible
+        # we should be able to create the TemplateResource object, but
+        # validation should fail, when the second attempt to access it is
+        # made in validate()
+        env = environment.Environment()
+        test_templ_name = 'http://heatr/noexist.yaml'
+        env.load({'resource_registry':
+                  {'Test::Flippy': test_templ_name}})
+        stack = parser.Stack(utils.dummy_context(), 'test_stack',
+                             parser.Template({}), env=env,
+                             stack_id=uuidutils.generate_uuid())
+
+        self.m.StubOutWithMock(urlfetch, "get")
+        urlfetch.get(test_templ_name,
+                     allowed_schemes=('http', 'https')).AndRaise(IOError)
+        urlfetch.get(test_templ_name,
+                     allowed_schemes=('http', 'https')).AndRaise(IOError)
+        self.m.ReplayAll()
+
+        temp_res = template_resource.TemplateResource('test_t_res',
+                                                      {"Type": 'Test::Flippy'},
+                                                      stack)
+        self.assertRaises(exception.StackValidationFailed, temp_res.validate)
+        self.m.VerifyAll()