]> review.fuel-infra Code Review - openstack-build/heat-build.git/commitdiff
Validate created/updated stacks in StackResource
authorChristopher Armstrong <chris.armstrong@rackspace.com>
Thu, 8 Aug 2013 23:00:29 +0000 (23:00 +0000)
committerChristopher Armstrong <chris.armstrong@rackspace.com>
Fri, 9 Aug 2013 21:36:36 +0000 (21:36 +0000)
StackResource.create_with_template and update_with_template now validate
the resulting stacks.

Change-Id: I52a81edb2af6bee70146f6dbd2179900e580d69b

heat/engine/stack_resource.py
heat/tests/test_autoscaling.py
heat/tests/test_instance_group.py
heat/tests/test_stack_resource.py

index 5c436361bc8bd0c553cde0edf9869b55ee638e9e..edc9480506957c3fca32ec4ac73027146701a7ad 100644 (file)
@@ -68,14 +68,15 @@ class StackResource(resource.Resource):
 
         # Note we disable rollback for nested stacks, since they
         # should be rolled back by the parent stack on failure
-        self._nested = parser.Stack(self.context,
-                                    self.physical_resource_name(),
-                                    template,
-                                    environment.Environment(user_params),
-                                    timeout_mins=timeout_mins,
-                                    disable_rollback=True,
-                                    parent_resource=self)
-
+        nested = parser.Stack(self.context,
+                              self.physical_resource_name(),
+                              template,
+                              environment.Environment(user_params),
+                              timeout_mins=timeout_mins,
+                              disable_rollback=True,
+                              parent_resource=self)
+        nested.validate()
+        self._nested = nested
         nested_id = self._nested.store(self.stack)
         self.resource_id_set(nested_id)
 
@@ -112,6 +113,7 @@ class StackResource(resource.Resource):
                              timeout_mins=timeout_mins,
                              disable_rollback=True,
                              parent_resource=self)
+        stack.validate()
         return self._nested.update(stack)
 
     def delete_nested(self):
index 110e41bf3504e4b914e55583fa9400c76b1eea86..e45d7ed3114cf9df8c57931ebb84816ddb181d94 100644 (file)
@@ -124,8 +124,12 @@ class AutoScalingTest(HeatTestCase):
         self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
         return rsrc
 
-    def _stub_create(self, num):
+    def _stub_validate(self):
+        self.m.StubOutWithMock(parser.Stack, 'validate')
+        parser.Stack.validate().MultipleTimes()
 
+    def _stub_create(self, num):
+        self._stub_validate()
         self.m.StubOutWithMock(instance.Instance, 'handle_create')
         self.m.StubOutWithMock(instance.Instance, 'check_create_complete')
         cookie = object()
@@ -450,6 +454,7 @@ class AutoScalingTest(HeatTestCase):
         t = template_format.parse(as_template)
         stack = utils.parse_stack(t, params=self.params)
 
+        self._stub_validate()
         self.m.StubOutWithMock(instance.Instance, 'handle_create')
         self.m.StubOutWithMock(instance.Instance, 'check_create_complete')
         instance.Instance.handle_create().AndRaise(Exception)
@@ -661,6 +666,7 @@ class AutoScalingTest(HeatTestCase):
 
         # reduce to 1
         self._stub_lb_reload(1)
+        self._stub_validate()
         self._stub_meta_expected(now, 'ChangeInCapacity : -2')
         self.m.ReplayAll()
         rsrc.adjust(-2)
@@ -678,6 +684,7 @@ class AutoScalingTest(HeatTestCase):
 
         # set to 2
         self._stub_lb_reload(2)
+        self._stub_validate()
         self._stub_meta_expected(now, 'ExactCapacity : 2')
         self.m.ReplayAll()
         rsrc.adjust(2, 'ExactCapacity')
@@ -704,6 +711,7 @@ class AutoScalingTest(HeatTestCase):
         self.m.StubOutWithMock(instance.Instance, 'handle_create')
         instance.Instance.handle_create().AndRaise(Exception)
         self._stub_lb_reload(1, unset=False, nochange=True)
+        self._stub_validate()
         self.m.ReplayAll()
 
         rsrc.adjust(1)
@@ -765,6 +773,7 @@ class AutoScalingTest(HeatTestCase):
         # reduce by 50%
         self._stub_lb_reload(1)
         self._stub_meta_expected(now, 'PercentChangeInCapacity : -50')
+        self._stub_validate()
         self.m.ReplayAll()
         rsrc.adjust(-50, 'PercentChangeInCapacity')
         self.assertEqual(['WebServerGroup-0'],
@@ -802,6 +811,7 @@ class AutoScalingTest(HeatTestCase):
 
         # reduce by 50%
         self._stub_lb_reload(1)
+        self._stub_validate()
         self._stub_meta_expected(now, 'PercentChangeInCapacity : -50')
         self.m.ReplayAll()
         rsrc.adjust(-50, 'PercentChangeInCapacity')
@@ -855,6 +865,7 @@ class AutoScalingTest(HeatTestCase):
 
         # reduce by 50%
         self._stub_lb_reload(1)
+        self._stub_validate()
         self._stub_meta_expected(now, 'PercentChangeInCapacity : -50')
         self.m.ReplayAll()
         rsrc.adjust(-50, 'PercentChangeInCapacity')
@@ -909,6 +920,7 @@ class AutoScalingTest(HeatTestCase):
         # reduce by 50%
         self._stub_lb_reload(1)
         self._stub_meta_expected(now, 'PercentChangeInCapacity : -50')
+        self._stub_validate()
         self.m.ReplayAll()
         rsrc.adjust(-50, 'PercentChangeInCapacity')
         self.assertEqual(['WebServerGroup-0'],
@@ -994,6 +1006,7 @@ class AutoScalingTest(HeatTestCase):
 
         # Scale down one
         self._stub_lb_reload(1)
+        self._stub_validate()
         self._stub_meta_expected(now, 'ChangeInCapacity : -1', 2)
 
         self.m.StubOutWithMock(asc.ScalingPolicy, 'keystone')
index 37109fa9b3a0ec1a5ae8a0a289930c4dd99526b3..c4f554e8f3df870baa1790c4a8087870622a9d93 100644 (file)
@@ -21,6 +21,7 @@ from heat.engine.resources import instance
 from heat.engine import resource
 from heat.engine import resources
 from heat.engine import scheduler
+from heat.engine import parser
 from heat.tests.common import HeatTestCase
 from heat.tests import utils
 
@@ -67,10 +68,13 @@ class InstanceGroupTest(HeatTestCase):
         :param instance_class: The resource class to expect to be created
                                instead of instance.Instance.
         """
+        self.m.StubOutWithMock(parser.Stack, 'validate')
+        parser.Stack.validate()
 
         self.m.StubOutWithMock(instance_class, 'handle_create')
         self.m.StubOutWithMock(instance_class, 'check_create_complete')
         cookie = object()
+
         for x in range(num):
             instance_class.handle_create().AndReturn(cookie)
         instance_class.check_create_complete(cookie).AndReturn(False)
@@ -147,6 +151,8 @@ class InstanceGroupTest(HeatTestCase):
         self.m.StubOutWithMock(instance.Instance, 'handle_create')
         not_found = exception.ImageNotFound(image_name='bla')
         instance.Instance.handle_create().AndRaise(not_found)
+        self.m.StubOutWithMock(parser.Stack, 'validate')
+        parser.Stack.validate()
 
         self.m.ReplayAll()
 
index 2819de04e71552d8e534b647c0b5a7721605652f..7eb7e7593da84bc6f0a35eb50b4a33374c16eedc 100644 (file)
@@ -25,15 +25,14 @@ from heat.tests.common import HeatTestCase
 from heat.tests import generic_resource as generic_rsrc
 from heat.tests import utils
 
+
 ws_res_snippet = {"Type": "some_magic_type",
                   "metadata": {
                       "key": "value",
                       "some": "more stuff"}}
 
-wp_template = '''
+param_template = '''
 {
-  "AWSTemplateFormatVersion" : "2010-09-09",
-  "Description" : "WordPress",
   "Parameters" : {
     "KeyName" : {
       "Description" : "KeyName",
@@ -43,24 +42,16 @@ wp_template = '''
   },
   "Resources" : {
     "WebServer": {
-      "Type": "AWS::EC2::Instance",
-      "metadata": {"Fn::ResourceFacade": "Metadata"},
-      "Properties": {
-        "ImageId" : "F17-x86_64-gold",
-        "InstanceType"   : "m1.large",
-        "KeyName"        : "test",
-        "UserData"       : "wordpress"
-      }
+      "Type": "GenericResource",
+      "Properties": {}
     }
   }
 }
 '''
 
 
-generic_template = '''
+simple_template = '''
 {
-  "AWSTemplateFormatVersion" : "2010-09-09",
-  "Description" : "WordPress",
   "Parameters" : {},
   "Resources" : {
     "WebServer": {
@@ -105,8 +96,8 @@ class StackResourceTest(HeatTestCase):
         self.parent_resource = MyStackResource('test',
                                                ws_res_snippet,
                                                self.parent_stack)
-        self.templ = template_format.parse(wp_template)
-        self.generic_template = template_format.parse(generic_template)
+        self.templ = template_format.parse(param_template)
+        self.simple_template = template_format.parse(simple_template)
 
     @utils.stack_delete_after
     def test_create_with_template_ok(self):
@@ -120,6 +111,36 @@ class StackResourceTest(HeatTestCase):
         self.assertEqual(self.templ, self.stack.t.t)
         self.assertEqual(self.stack.id, self.parent_resource.resource_id)
 
+    @utils.stack_delete_after
+    def test_create_with_template_validates(self):
+        """
+        Creating a stack with a template validates the created stack, so that
+        an invalid template will cause an error to be raised.
+        """
+        # Make a parameter key with the same name as the resource to cause a
+        # simple validation error
+        template = self.simple_template.copy()
+        template['Parameters']['WebServer'] = {'Type': 'String'}
+        self.assertRaises(
+            exception.StackValidationFailed,
+            self.parent_resource.create_with_template,
+            template, {'WebServer': 'foo'})
+
+    @utils.stack_delete_after
+    def test_update_with_template_validates(self):
+        """Updating a stack with a template validates the created stack."""
+        create_result = self.parent_resource.create_with_template(
+            self.simple_template, {})
+        while not create_result.step():
+            pass
+
+        template = self.simple_template.copy()
+        template['Parameters']['WebServer'] = {'Type': 'String'}
+        self.assertRaises(
+            exception.StackValidationFailed,
+            self.parent_resource.update_with_template,
+            template, {'WebServer': 'foo'})
+
     @utils.stack_delete_after
     def test_update_with_template_ok(self):
         """
@@ -127,12 +148,12 @@ class StackResourceTest(HeatTestCase):
         given template and user parameters.
         """
         create_result = self.parent_resource.create_with_template(
-            self.generic_template, {})
+            self.simple_template, {})
         while not create_result.step():
             pass
         self.stack = self.parent_resource.nested()
 
-        new_templ = self.generic_template.copy()
+        new_templ = self.simple_template.copy()
         inst_snippet = new_templ["Resources"]["WebServer"].copy()
         new_templ["Resources"]["WebServer2"] = inst_snippet
         update_result = self.parent_resource.update_with_template(