diff --git a/heat/engine/service.py b/heat/engine/service.py index 9734ecd5bd..4642618ab4 100644 --- a/heat/engine/service.py +++ b/heat/engine/service.py @@ -595,7 +595,10 @@ class EngineService(service.Service): return webob.exc.HTTPBadRequest(explanation=msg) tmpl = parser.Template(template) - tmpl_resources = tmpl.get('Resources', []) + try: + tmpl_resources = tmpl['Resources'] + except KeyError as ex: + return {'Error': str(ex)} if not tmpl_resources: return {'Error': 'At least one Resources member must be defined.'} diff --git a/heat/tests/test_hot.py b/heat/tests/test_hot.py index 8b3603c499..f38c922f84 100644 --- a/heat/tests/test_hot.py +++ b/heat/tests/test_hot.py @@ -131,7 +131,9 @@ class HOTemplateTest(HeatTestCase): tmpl = parser.Template(hot_tpl) err = self.assertRaises(KeyError, tmpl.__getitem__, tmpl.RESOURCES) - self.assertIn('Type', str(err)) + self.assertEqual('u\'"Type" is not a valid keyword ' + 'inside a resource definition\'', + str(err)) def test_translate_resources_bad_properties(self): """Test translation of resources including invalid keyword.""" @@ -153,7 +155,9 @@ class HOTemplateTest(HeatTestCase): tmpl = parser.Template(hot_tpl) err = self.assertRaises(KeyError, tmpl.__getitem__, tmpl.RESOURCES) - self.assertIn('Properties', str(err)) + self.assertEqual('u\'"Properties" is not a valid keyword ' + 'inside a resource definition\'', + str(err)) def test_translate_resources_bad_metadata(self): """Test translation of resources including invalid keyword.""" @@ -175,7 +179,9 @@ class HOTemplateTest(HeatTestCase): tmpl = parser.Template(hot_tpl) err = self.assertRaises(KeyError, tmpl.__getitem__, tmpl.RESOURCES) - self.assertIn('Metadata', str(err)) + self.assertEqual('u\'"Metadata" is not a valid keyword ' + 'inside a resource definition\'', + str(err)) def test_translate_resources_bad_depends_on(self): """Test translation of resources including invalid keyword.""" @@ -197,7 +203,9 @@ class HOTemplateTest(HeatTestCase): tmpl = parser.Template(hot_tpl) err = self.assertRaises(KeyError, tmpl.__getitem__, tmpl.RESOURCES) - self.assertIn('DependsOn', str(err)) + self.assertEqual('u\'"DependsOn" is not a valid keyword ' + 'inside a resource definition\'', + str(err)) def test_translate_resources_bad_deletion_polciy(self): """Test translation of resources including invalid keyword.""" @@ -219,7 +227,9 @@ class HOTemplateTest(HeatTestCase): tmpl = parser.Template(hot_tpl) err = self.assertRaises(KeyError, tmpl.__getitem__, tmpl.RESOURCES) - self.assertIn('DeletionPolicy', str(err)) + self.assertEqual('u\'"DeletionPolicy" is not a valid keyword ' + 'inside a resource definition\'', + str(err)) def test_translate_resources_bad_update_policy(self): """Test translation of resources including invalid keyword.""" @@ -241,7 +251,9 @@ class HOTemplateTest(HeatTestCase): tmpl = parser.Template(hot_tpl) err = self.assertRaises(KeyError, tmpl.__getitem__, tmpl.RESOURCES) - self.assertIn('UpdatePolicy', str(err)) + self.assertEqual('u\'"UpdatePolicy" is not a valid keyword ' + 'inside a resource definition\'', + str(err)) def test_translate_outputs_good(self): """Test translation of outputs into internal engine format.""" diff --git a/heat/tests/test_validate.py b/heat/tests/test_validate.py index fdb2edee39..bdf8f30739 100644 --- a/heat/tests/test_validate.py +++ b/heat/tests/test_validate.py @@ -1028,6 +1028,172 @@ class validateTest(HeatTestCase): res = dict(engine.validate_template(None, t)) self.assertEqual({'Description': u'test.', 'Parameters': {}}, res) + def test_validate_template_without_resources(self): + hot_tpl = template_format.parse(''' + heat_template_version: 2013-05-23 + ''') + + self.m.StubOutWithMock(service.EngineListener, 'start') + service.EngineListener.start().AndReturn(None) + self.m.ReplayAll() + + engine = service.EngineService('a', 't') + res = dict(engine.validate_template(None, hot_tpl)) + self.assertEqual({'Error': 'At least one Resources member ' + 'must be defined.'}, res) + + def test_validate_template_with_invalid_resource_type(self): + hot_tpl = template_format.parse(''' + heat_template_version: 2013-05-23 + resources: + resource1: + Type: AWS::EC2::Instance + properties: + property1: value1 + metadata: + foo: bar + depends_on: dummy + deletion_policy: dummy + update_policy: + foo: bar + ''') + + self.m.StubOutWithMock(service.EngineListener, 'start') + service.EngineListener.start().AndReturn(None) + self.m.ReplayAll() + + engine = service.EngineService('a', 't') + res = dict(engine.validate_template(None, hot_tpl)) + self.assertEqual({'Error': 'u\'"Type" is not a valid keyword ' + 'inside a resource definition\''}, res) + + def test_validate_template_with_invalid_resource_properties(self): + hot_tpl = template_format.parse(''' + heat_template_version: 2013-05-23 + resources: + resource1: + type: AWS::EC2::Instance + Properties: + property1: value1 + metadata: + foo: bar + depends_on: dummy + deletion_policy: dummy + update_policy: + foo: bar + ''') + + self.m.StubOutWithMock(service.EngineListener, 'start') + service.EngineListener.start().AndReturn(None) + self.m.ReplayAll() + + engine = service.EngineService('a', 't') + res = dict(engine.validate_template(None, hot_tpl)) + self.assertEqual({'Error': 'u\'"Properties" is not a valid keyword ' + 'inside a resource definition\''}, res) + + def test_validate_template_with_invalid_resource_matadata(self): + hot_tpl = template_format.parse(''' + heat_template_version: 2013-05-23 + resources: + resource1: + type: AWS::EC2::Instance + properties: + property1: value1 + Metadata: + foo: bar + depends_on: dummy + deletion_policy: dummy + update_policy: + foo: bar + ''') + + self.m.StubOutWithMock(service.EngineListener, 'start') + service.EngineListener.start().AndReturn(None) + self.m.ReplayAll() + + engine = service.EngineService('a', 't') + res = dict(engine.validate_template(None, hot_tpl)) + self.assertEqual({'Error': 'u\'"Metadata" is not a valid keyword ' + 'inside a resource definition\''}, res) + + def test_validate_template_with_invalid_resource_depends_on(self): + hot_tpl = template_format.parse(''' + heat_template_version: 2013-05-23 + resources: + resource1: + type: AWS::EC2::Instance + properties: + property1: value1 + metadata: + foo: bar + DependsOn: dummy + deletion_policy: dummy + update_policy: + foo: bar + ''') + + self.m.StubOutWithMock(service.EngineListener, 'start') + service.EngineListener.start().AndReturn(None) + self.m.ReplayAll() + + engine = service.EngineService('a', 't') + res = dict(engine.validate_template(None, hot_tpl)) + self.assertEqual({'Error': 'u\'"DependsOn" is not a valid keyword ' + 'inside a resource definition\''}, res) + + def test_validate_template_with_invalid_resource_deletion_polciy(self): + hot_tpl = template_format.parse(''' + heat_template_version: 2013-05-23 + resources: + resource1: + type: AWS::EC2::Instance + properties: + property1: value1 + metadata: + foo: bar + depends_on: dummy + DeletionPolicy: dummy + update_policy: + foo: bar + ''') + + self.m.StubOutWithMock(service.EngineListener, 'start') + service.EngineListener.start().AndReturn(None) + self.m.ReplayAll() + + engine = service.EngineService('a', 't') + res = dict(engine.validate_template(None, hot_tpl)) + self.assertEqual({'Error': 'u\'"DeletionPolicy" is not a valid ' + 'keyword inside a resource definition\''}, + res) + + def test_validate_template_with_invalid_resource_update_policy(self): + hot_tpl = template_format.parse(''' + heat_template_version: 2013-05-23 + resources: + resource1: + type: AWS::EC2::Instance + properties: + property1: value1 + metadata: + foo: bar + depends_on: dummy + deletion_policy: dummy + UpdatePolicy: + foo: bar + ''') + + self.m.StubOutWithMock(service.EngineListener, 'start') + service.EngineListener.start().AndReturn(None) + self.m.ReplayAll() + + engine = service.EngineService('a', 't') + res = dict(engine.validate_template(None, hot_tpl)) + self.assertEqual({'Error': 'u\'"UpdatePolicy" is not a valid ' + 'keyword inside a resource definition\''}, + res) + def test_unregistered_key(self): t = template_format.parse(test_unregistered_key) template = parser.Template(t)