From: Thomas Herve Date: Mon, 29 Apr 2013 15:21:42 +0000 (+0200) Subject: Validate properties against the schema in validate_template X-Git-Tag: 2014.1~685^2 X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=25dfc5f062b5c8a9f9266173607c199931b4c07e;p=openstack-build%2Fheat-build.git Validate properties against the schema in validate_template Change-Id: I81457d8d363226b90b2a878ec2c93f88b376dc83 Fixes: bug #1154722 --- diff --git a/heat/engine/properties.py b/heat/engine/properties.py index 0cd808ef..d0351794 100644 --- a/heat/engine/properties.py +++ b/heat/engine/properties.py @@ -172,13 +172,14 @@ class Properties(collections.Mapping): else: self.error_prefix = parent_name + ': ' - def validate(self): + def validate(self, with_value=True): for (key, prop) in self.props.items(): - try: - self[key] - except ValueError as e: - msg = "Property error : %s" % str(e) - raise exception.StackValidationFailed(message=msg) + if with_value: + try: + self[key] + except ValueError as e: + msg = "Property error : %s" % str(e) + raise exception.StackValidationFailed(message=msg) # are there unimplemented Properties if not prop.implemented() and key in self.data: diff --git a/heat/engine/service.py b/heat/engine/service.py index efd962c1..484fee10 100644 --- a/heat/engine/service.py +++ b/heat/engine/service.py @@ -28,6 +28,7 @@ from heat.common import exception from heat.common import identifier from heat.engine import parameters from heat.engine import parser +from heat.engine import properties from heat.engine import resource from heat.engine import resources # pyflakes_bypass review 23102 from heat.engine import watchrule @@ -286,6 +287,13 @@ class EngineService(service.Service): if not res.get('Type'): return {'Error': 'Every Resources object must contain a Type member.'} + ResourceClass = resource.get_class(res['Type']) + props = properties.Properties(ResourceClass.properties_schema, + res.get('Properties', {})) + try: + props.validate(with_value=False) + except Exception as ex: + return {'Error': str(ex)} tmpl_params = parser.Parameters(None, tmpl) format_validate_parameter = lambda p: dict(p.schema) diff --git a/heat/tests/test_validate.py b/heat/tests/test_validate.py index 8c9a51b6..480bfe35 100644 --- a/heat/tests/test_validate.py +++ b/heat/tests/test_validate.py @@ -207,6 +207,64 @@ test_template_findinmap_invalid = ''' } ''' +test_template_invalid_property = ''' +{ + "AWSTemplateFormatVersion" : "2010-09-09", + "Description" : "test.", + "Parameters" : { + + "KeyName" : { +''' + \ + '"Description" : "Name of an existing EC2' + \ + 'KeyPair to enable SSH access to the instances",' + \ + ''' + "Type" : "String" + } + }, + + "Resources" : { + "WikiDatabase": { + "Type": "AWS::EC2::Instance", + "Properties": { + "ImageId": "image_name", + "InstanceType": "m1.large", + "KeyName": { "Ref" : "KeyName" }, + "UnknownProperty": "unknown" + } + } + } + } + ''' + +test_template_unimplemented_property = ''' +{ + "AWSTemplateFormatVersion" : "2010-09-09", + "Description" : "test.", + "Parameters" : { + + "KeyName" : { +''' + \ + '"Description" : "Name of an existing EC2' + \ + 'KeyPair to enable SSH access to the instances",' + \ + ''' + "Type" : "String" + } + }, + + "Resources" : { + "WikiDatabase": { + "Type": "AWS::EC2::Instance", + "Properties": { + "ImageId": "image_name", + "InstanceType": "m1.large", + "KeyName": { "Ref" : "KeyName" }, + "SourceDestCheck": "false" + } + } + } + } + ''' + @attr(tag=['unit', 'validate']) @attr(speed='fast') @@ -302,3 +360,25 @@ class validateTest(unittest.TestCase): 'Type': 'String', 'Description': 'Name of an existing EC2KeyPair to enable SSH ' 'access to the instances'}}) + + def test_validate_properties(self): + t = template_format.parse(test_template_invalid_property) + self.m.StubOutWithMock(instances.Instance, 'nova') + instances.Instance.nova().AndReturn(self.fc) + self.m.ReplayAll() + + engine = service.EngineService('a', 't') + res = dict(engine.validate_template(None, t)) + self.assertEqual(res, {'Error': 'Unknown Property UnknownProperty'}) + + def test_unimplemented_property(self): + t = template_format.parse(test_template_unimplemented_property) + self.m.StubOutWithMock(instances.Instance, 'nova') + instances.Instance.nova().AndReturn(self.fc) + self.m.ReplayAll() + + engine = service.EngineService('a', 't') + res = dict(engine.validate_template(None, t)) + self.assertEqual( + res, + {'Error': 'Property SourceDestCheck not implemented yet'})