]> review.fuel-infra Code Review - openstack-build/heat-build.git/commitdiff
Create autoscaling instances in parallel
authorZane Bitter <zbitter@redhat.com>
Mon, 4 Mar 2013 10:31:27 +0000 (11:31 +0100)
committerZane Bitter <zbitter@redhat.com>
Mon, 4 Mar 2013 10:38:39 +0000 (11:38 +0100)
Fixes bug #1136148

Change-Id: I02ea52df85c4ed7f0f16abcfd1ab24b35168a787
Signed-off-by: Zane Bitter <zbitter@redhat.com>
heat/engine/resources/autoscaling.py
heat/tests/test_autoscaling.py
heat/tests/test_instance_group.py

index ed1db3368759c38961a4d2b74eb9bad0a130c795..dc0b1023dd8c2f2279115006fd7b46070cd1e721 100644 (file)
@@ -13,6 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import eventlet
+
 from heat.common import exception
 from heat.engine import resource
 
@@ -75,11 +77,21 @@ class InstanceGroup(resource.Resource):
 
     def __init__(self, name, json_snippet, stack):
         super(InstanceGroup, self).__init__(name, json_snippet, stack)
-        # resource_id is a list of resources
+        self._activating = []
 
     def handle_create(self):
         self.resize(int(self.properties['Size']), raise_on_error=True)
 
+    def check_active(self):
+        active = all(i.check_active(override=False) for i in self._activating)
+        if active:
+            self._activating = []
+        return active
+
+    def _wait_for_activation(self):
+        while not self.check_active():
+            eventlet.sleep(1)
+
     def handle_update(self, json_snippet):
         try:
             tmpl_diff = self.update_template_diff(json_snippet)
@@ -111,6 +123,7 @@ class InstanceGroup(resource.Resource):
                 if len(inst_list) != int(self.properties['Size']):
                     self.resize(int(self.properties['Size']),
                                 raise_on_error=True)
+                    self._wait_for_activation()
 
         return self.UPDATE_COMPLETE
 
@@ -128,6 +141,15 @@ class InstanceGroup(resource.Resource):
             def state_set(self, new_state, reason="state changed"):
                 self._store_or_update(new_state, reason)
 
+            def check_active(self, override=True):
+                '''
+                By default, report that the instance is active so that we
+                won't wait for it in create().
+                '''
+                if override:
+                    return True
+                return super(GroupedInstance, self).check_active()
+
         conf = self.properties['LaunchConfigurationName']
         instance_definition = self.stack.t['Resources'][conf]
         return GroupedInstance(name, instance_definition, self.stack)
@@ -163,6 +185,7 @@ class InstanceGroup(resource.Resource):
                 name = '%s-%d' % (self.name, x)
                 inst = self._make_instance(name)
                 inst_list.append(name)
+                self._activating.append(inst)
                 self.resource_id_set(','.join(inst_list))
                 logger.info('creating inst')
                 error_str = inst.create()
@@ -298,11 +321,13 @@ class AutoScalingGroup(InstanceGroup, CooldownMixin):
 
             if new_capacity is not None:
                 self._adjust(new_capacity)
+                self._wait_for_activation()
 
         return self.UPDATE_COMPLETE
 
     def adjust(self, adjustment, adjustment_type='ChangeInCapacity'):
         self._adjust(adjustment, adjustment_type, False)
+        self._wait_for_activation()
 
     def _adjust(self, adjustment, adjustment_type='ExactCapacity',
                 raise_on_error=True):
index 026c82c6d4a26827258bcc3a693fc74761dfd46d..57e7e1a1086c8268279e3b6bdbd41cca5ecb9bf5 100644 (file)
@@ -17,6 +17,7 @@ import os
 import datetime
 import copy
 
+import eventlet
 import unittest
 import mox
 
@@ -83,9 +84,15 @@ class AutoScalingTest(unittest.TestCase):
         return resource
 
     def _stub_create(self, num):
+        self.m.StubOutWithMock(eventlet, 'sleep')
+
         self.m.StubOutWithMock(instance.Instance, 'create')
+        self.m.StubOutWithMock(instance.Instance, 'check_active')
         for x in range(num):
             instance.Instance.create().AndReturn(None)
+        instance.Instance.check_active().AndReturn(False)
+        eventlet.sleep(mox.IsA(int)).AndReturn(None)
+        instance.Instance.check_active().MultipleTimes().AndReturn(True)
 
     def _stub_lb_reload(self, expected_list, unset=True):
         if unset:
index fdc255ee170bdd43d730107cab36d1019246ab04..be9d3d383f04d6ca7fcf63f8c84eebf0cbd5a18c 100644 (file)
@@ -15,6 +15,7 @@
 import copy
 import os
 
+import eventlet
 import unittest
 import mox
 
@@ -62,9 +63,15 @@ class InstanceGroupTest(unittest.TestCase):
         return stack
 
     def _stub_create(self, num):
+        self.m.StubOutWithMock(eventlet, 'sleep')
+
         self.m.StubOutWithMock(instance.Instance, 'create')
+        self.m.StubOutWithMock(instance.Instance, 'check_active')
         for x in range(num):
             instance.Instance.create().AndReturn(None)
+        instance.Instance.check_active().AndReturn(False)
+        eventlet.sleep(mox.IsA(int)).AndReturn(None)
+        instance.Instance.check_active().MultipleTimes().AndReturn(True)
 
     def create_instance_group(self, t, stack, resource_name):
         resource = asc.InstanceGroup(resource_name,