From 51390e8ba70cc22202e27f972455af66d3dbe779 Mon Sep 17 00:00:00 2001 From: Sergey Kraynev Date: Mon, 24 Nov 2014 08:04:12 -0500 Subject: [PATCH] Handle error with non existing template file This patch allows to propagate IOError instead of returning TemplateResource which does not contain property_schema. Change-Id: Ib1e09de8c10672312eea09f62a28f0885d98b089 Closes-Bug: #1394552 --- heat/engine/resource.py | 9 ++++--- heat/engine/resources/template_resource.py | 3 ++- heat/engine/service.py | 4 ++++ heat/tests/test_engine_service.py | 28 +++++++++++++++++++--- heat/tests/test_provider_template.py | 11 +++++---- 5 files changed, 43 insertions(+), 12 deletions(-) diff --git a/heat/engine/resource.py b/heat/engine/resource.py index 8d640e866..f2dd31d36 100644 --- a/heat/engine/resource.py +++ b/heat/engine/resource.py @@ -142,9 +142,12 @@ class Resource(object): return res_info.template_name not in ancestor_list registry = stack.env.registry - ResourceClass = registry.get_class(definition.resource_type, - resource_name=name, - accept_fn=accept_class) + try: + ResourceClass = registry.get_class(definition.resource_type, + resource_name=name, + accept_fn=accept_class) + except exception.NotFound: + ResourceClass = template_resource.TemplateResource assert issubclass(ResourceClass, Resource) return super(Resource, cls).__new__(ResourceClass) diff --git a/heat/engine/resources/template_resource.py b/heat/engine/resources/template_resource.py index d959a69fa..9502a03c7 100644 --- a/heat/engine/resources/template_resource.py +++ b/heat/engine/resources/template_resource.py @@ -32,7 +32,8 @@ def generate_class(name, template_name): try: data = urlfetch.get(template_name, allowed_schemes=('file',)) except IOError: - return TemplateResource + msg = _('No such file: %s') % template_name + raise exception.NotFound(msg_fmt=msg) tmpl = template.Template(template_format.parse(data)) properties_schema = properties.Properties.schema_from_params( tmpl.param_schemata()) diff --git a/heat/engine/service.py b/heat/engine/service.py index d5fbf3540..b24475f20 100644 --- a/heat/engine/service.py +++ b/heat/engine/service.py @@ -974,6 +974,8 @@ class EngineService(service.Service): resource_class = resources.global_env().get_class(type_name) except exception.StackValidationFailed: raise exception.ResourceTypeNotFound(type_name=type_name) + except exception.NotFound as ex: + raise exception.StackValidationFailed(message=ex.message) def properties_schema(): for name, schema_dict in resource_class.properties_schema.items(): @@ -1004,6 +1006,8 @@ class EngineService(service.Service): type_name).resource_to_template(type_name) except exception.StackValidationFailed: raise exception.ResourceTypeNotFound(type_name=type_name) + except exception.NotFound as ex: + raise exception.StackValidationFailed(message=ex.message) @request_context def list_events(self, cnxt, stack_identity, filters=None, limit=None, diff --git a/heat/tests/test_engine_service.py b/heat/tests/test_engine_service.py index a019c0057..1ca478489 100644 --- a/heat/tests/test_engine_service.py +++ b/heat/tests/test_engine_service.py @@ -2265,10 +2265,32 @@ class StackServiceTest(common.HeatTestCase): schema = self.eng.resource_schema(self.ctx, type_name=type_name) self.assertEqual(expected, schema) + def _no_template_file(self, function): + info = environment.ResourceInfo(environment.ResourceRegistry, + ['ResourceWithWrongRefOnFile'], + 'not_existing.yaml') + mock_iterable = mock.MagicMock(return_value=iter([info])) + with mock.patch('heat.engine.environment.ResourceRegistry.iterable_by', + new=mock_iterable): + ex = self.assertRaises(exception.StackValidationFailed, + function, + self.ctx, + type_name='ResourceWithWrongRefOnFile') + msg = 'No such file: not_existing.yaml' + self.assertIn(msg, six.text_type(ex)) + + def test_resource_schema_no_template_file(self): + self._no_template_file(self.eng.resource_schema) + + def test_generate_template_no_template_file(self): + self._no_template_file(self.eng.generate_template) + def test_resource_schema_nonexist(self): - self.assertRaises(exception.ResourceTypeNotFound, - self.eng.resource_schema, - self.ctx, type_name='Bogus') + ex = self.assertRaises(exception.ResourceTypeNotFound, + self.eng.resource_schema, + self.ctx, type_name='Bogus') + msg = 'The Resource Type (Bogus) could not be found.' + self.assertEqual(msg, six.text_type(ex)) @stack_context('service_stack_resource_describe__test_stack') def test_stack_resource_describe(self): diff --git a/heat/tests/test_provider_template.py b/heat/tests/test_provider_template.py index 561ba6566..9c127b62c 100644 --- a/heat/tests/test_provider_template.py +++ b/heat/tests/test_provider_template.py @@ -435,14 +435,15 @@ class ProviderTemplateTest(common.HeatTestCase): definition, stack) self.assertIsNone(temp_res.validate()) - def test_get_template_resource(self): - # assertion: if the name matches {.yaml|.template} we get the - # TemplateResource class. + def test_get_error_for_invalid_template_name(self): + # assertion: if the name matches {.yaml|.template} and is valid + # we get the TemplateResource class, otherwise error will be raised. env_str = {'resource_registry': {'resources': {'fred': { "OS::ResourceType": "some_magic.yaml"}}}} env = environment.Environment(env_str) - cls = env.get_class('OS::ResourceType', 'fred') - self.assertEqual(template_resource.TemplateResource, cls) + ex = self.assertRaises(exception.NotFound, env.get_class, + 'OS::ResourceType', 'fred') + self.assertEqual('No such file: some_magic.yaml', six.text_type(ex)) def test_get_template_resource_class(self): test_templ_name = 'file:///etc/heatr/frodo.yaml'