]> review.fuel-infra Code Review - openstack-build/heat-build.git/commitdiff
Validate properties against the schema in validate_template
authorThomas Herve <therve@gmail.com>
Mon, 29 Apr 2013 15:21:42 +0000 (17:21 +0200)
committerThomas Herve <therve@gmail.com>
Mon, 29 Apr 2013 16:19:55 +0000 (18:19 +0200)
Change-Id: I81457d8d363226b90b2a878ec2c93f88b376dc83
Fixes: bug #1154722
heat/engine/properties.py
heat/engine/service.py
heat/tests/test_validate.py

index 0cd808efe59f63e78f2b6b87070f67f14db354ea..d0351794ed8c055bac60243ec29dab703d861d87 100644 (file)
@@ -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:
index efd962c1ac115c51a58d160e50c5d618fe8a5414..484fee1017dfea2aae4211fcdd674b4c0dbdec05 100644 (file)
@@ -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)
index 8c9a51b63208cc674850775c7145a4ec3327c39f..480bfe35dffe1ea1705aea701f85d2dd513ffbe7 100644 (file)
@@ -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'})