Przeglądaj źródła

Made timeout and interval a globally configurable default, closing
issue: https://github.com/gvlproject/cloudbridge/issues/7

Nuwan Goonasekera 10 lat temu
rodzic
commit
76db9d36b8

+ 16 - 0
cloudbridge/cloud/base/impl.py

@@ -7,6 +7,8 @@ from cloudbridge.cloud.interfaces import CloudProvider
 from cloudbridge.cloud.interfaces.resources import Configuration
 
 DEFAULT_RESULT_LIMIT = 50
+DEFAULT_WAIT_TIMEOUT = 600
+DEFAULT_WAIT_INTERVAL = 5
 
 
 class BaseConfiguration(Configuration):
@@ -25,6 +27,20 @@ class BaseConfiguration(Configuration):
         """
         return self.get('default_result_limit', DEFAULT_RESULT_LIMIT)
 
+    @property
+    def default_wait_timeout(self):
+        """
+        Gets the default wait timeout for LifeCycleObjects.
+        """
+        return self.get('default_wait_timeout', DEFAULT_WAIT_TIMEOUT)
+
+    @property
+    def default_wait_interval(self):
+        """
+        Gets the default wait interval for LifeCycleObjects.
+        """
+        return self.get('default_wait_interval', DEFAULT_WAIT_INTERVAL)
+
     @property
     def debug_mode(self):
         """

+ 11 - 6
cloudbridge/cloud/base/resources.py

@@ -54,8 +54,13 @@ class BaseObjectLifeCycleMixin(ObjectLifeCycleMixin):
     method, since the desired ready states are object specific.
     """
 
-    def wait_for(self, target_states, terminal_states=None, timeout=600,
-                 interval=5):
+    def wait_for(self, target_states, terminal_states=None, timeout=None,
+                 interval=None):
+        if timeout is None:
+            timeout = self._provider.config.default_wait_timeout
+        if interval is None:
+            interval = self._provider.config.default_wait_interval
+
         assert timeout >= 0
         assert interval >= 0
         assert timeout >= interval
@@ -231,7 +236,7 @@ class BaseInstance(BaseCloudResource, BaseObjectLifeCycleMixin, Instance):
                 self.private_ips == other.private_ips and
                 self.image_id == other.image_id)
 
-    def wait_till_ready(self, timeout=600, interval=5):
+    def wait_till_ready(self, timeout=None, interval=None):
         self.wait_for(
             [InstanceState.RUNNING],
             terminal_states=[InstanceState.TERMINATED, InstanceState.ERROR],
@@ -324,7 +329,7 @@ class BaseMachineImage(
                 self.name == other.name and
                 self.description == other.description)
 
-    def wait_till_ready(self, timeout=600, interval=5):
+    def wait_till_ready(self, timeout=None, interval=None):
         self.wait_for(
             [MachineImageState.AVAILABLE],
             terminal_states=[MachineImageState.ERROR],
@@ -350,7 +355,7 @@ class BaseVolume(BaseCloudResource, BaseObjectLifeCycleMixin, Volume):
                 self.state == other.state and
                 self.name == other.name)
 
-    def wait_till_ready(self, timeout=600, interval=5):
+    def wait_till_ready(self, timeout=None, interval=None):
         self.wait_for(
             [VolumeState.AVAILABLE],
             terminal_states=[VolumeState.ERROR, VolumeState.DELETED],
@@ -376,7 +381,7 @@ class BaseSnapshot(BaseCloudResource, BaseObjectLifeCycleMixin, Snapshot):
                 self.state == other.state and
                 self.name == other.name)
 
-    def wait_till_ready(self, timeout=600, interval=5):
+    def wait_till_ready(self, timeout=None, interval=None):
         self.wait_for(
             [SnapshotState.AVAILABLE],
             terminal_states=[SnapshotState.ERROR],

+ 38 - 9
cloudbridge/cloud/interfaces/resources.py

@@ -81,14 +81,40 @@ class Configuration(dict):
     @abstractproperty
     def default_result_limit(self):
         """
-        Get the maximum number of results to return for a
-        list method
+        Get the default maximum number of results to return for a
+        list method. The default limit will be applied to most list()
+        and find() methods whenever an explicit limit is not specified.
 
         :rtype: ``int``
         :return: The maximum number of results to return
         """
         pass
 
+    @property
+    def default_wait_timeout(self):
+        """
+        Gets the default wait timeout for LifeCycleObjects. The default
+        wait timeout is applied in wait_for() and wait_till_ready() methods
+        if no explicit timeout is specified.
+
+        :rtype: ``int``
+        :return: The maximum length of time (in seconds) to wait for the
+                 object to change to desired state.
+        """
+        pass
+
+    @property
+    def default_wait_interval(self):
+        """
+        Gets the default wait interval for LifeCycleObjects. The default
+        wait interval is applied in wait_for() and wait_till_ready() methods
+        if no explicit interval is specified.
+
+        :rtype: ``int``
+        :return: How frequently to poll the object's state
+        """
+        pass
+
     @abstractproperty
     def debug_mode(self):
         """
@@ -151,8 +177,8 @@ class ObjectLifeCycleMixin(object):
         pass
 
     @abstractmethod
-    def wait_for(self, target_states, terminal_states=None, timeout=600,
-                 interval=5):
+    def wait_for(self, target_states, terminal_states=None, timeout=None,
+                 interval=None):
         """
         Wait for a specified timeout for an object to reach a set of desired
         target states. If the object does not reach the desired state within
@@ -168,8 +194,7 @@ class ObjectLifeCycleMixin(object):
 
             instance.wait_for(
                 [InstanceState.TERMINATED, InstanceState.UNKNOWN],
-                terminal_states=[InstanceState.ERROR],
-                interval=self.get_test_wait_interval())
+                terminal_states=[InstanceState.ERROR])
 
         :type target_states: ``list`` of states
         :param target_states: The list of target states to wait for.
@@ -181,11 +206,15 @@ class ObjectLifeCycleMixin(object):
 
         :type timeout: int
         :param timeout: The maximum length of time (in seconds) to wait for the
-                        object to become ready.
+                        object to changed to desired state. If no timeout is
+                        specified, the global default_wait_timeout defined in
+                        the provider config will apply.
 
         :type interval: int
-        :param interval: How frequently to poll the object's ready state (in
-                         seconds).
+        :param interval: How frequently to poll the object's state (in
+                         seconds). If no interval is specified, the global
+                         default_wait_interval defined in the provider config
+                         will apply.
 
         :rtype: ``True``
         :return: Returns ``True`` if successful. A ``WaitStateException``

+ 10 - 12
test/helpers.py

@@ -81,20 +81,13 @@ def create_test_instance(
         launch_config=launch_config)
 
 
-def get_provider_wait_interval(provider):
-    if isinstance(provider, TestMockHelperMixin):
-        return 0
-    else:
-        return 1
-
-
 def get_test_instance(provider, name, keypair=None, security_groups=None):
     instance = create_test_instance(
         provider,
         name,
         keypair=keypair,
         security_groups=security_groups)
-    instance.wait_till_ready(interval=get_provider_wait_interval(provider))
+    instance.wait_till_ready()
     return instance
 
 
@@ -142,9 +135,6 @@ class ProviderTestBase(object):
         if isinstance(self.provider, TestMockHelperMixin):
             self.provider.tearDownMock()
 
-    def get_test_wait_interval(self):
-        return get_provider_wait_interval(self.provider)
-
 
 class ProviderTestCaseGenerator():
 
@@ -156,12 +146,20 @@ class ProviderTestCaseGenerator():
     def __init__(self, test_classes):
         self.all_test_classes = test_classes
 
+    def get_provider_wait_interval(self, provider_class):
+        if issubclass(provider_class, TestMockHelperMixin):
+            return 0
+        else:
+            return 1
+
     def create_provider_instance(self, provider_class):
         """
         Instantiate a default provider instance. All required connection
         settings are expected to be set as environment variables.
         """
-        return provider_class({})
+        config = {'default_wait_interval':
+                  self.get_provider_wait_interval(provider_class)}
+        return provider_class(config)
 
     def generate_new_test_class(self, name, testcase_class):
         """

+ 9 - 16
test/test_block_store_service.py

@@ -25,13 +25,11 @@ class CloudBlockStoreServiceTestCase(ProviderTestBase):
 
         def cleanup_vol(vol):
             vol.delete()
-            vol.wait_for(
-                [VolumeState.DELETED, VolumeState.UNKNOWN],
-                terminal_states=[VolumeState.ERROR],
-                interval=self.get_test_wait_interval())
+            vol.wait_for([VolumeState.DELETED, VolumeState.UNKNOWN],
+                         terminal_states=[VolumeState.ERROR])
 
         with helpers.cleanup_action(lambda: cleanup_vol(test_vol)):
-            test_vol.wait_till_ready(interval=self.get_test_wait_interval())
+            test_vol.wait_till_ready()
             self.assertTrue(
                 test_vol.id in repr(test_vol),
                 "repr(obj) should contain the object id so that the object"
@@ -94,18 +92,15 @@ class CloudBlockStoreServiceTestCase(ProviderTestBase):
             test_vol = self.provider.block_store.volumes.create(
                 name, 1, test_instance.placement_zone)
             with helpers.cleanup_action(lambda: test_vol.delete()):
-                test_vol.wait_till_ready(
-                    interval=self.get_test_wait_interval())
+                test_vol.wait_till_ready()
                 test_vol.attach(test_instance, '/dev/sda2')
                 test_vol.wait_for(
                     [VolumeState.IN_USE],
-                    terminal_states=[VolumeState.ERROR, VolumeState.DELETED],
-                    interval=self.get_test_wait_interval())
+                    terminal_states=[VolumeState.ERROR, VolumeState.DELETED])
                 test_vol.detach()
                 test_vol.wait_for(
                     [VolumeState.AVAILABLE],
-                    terminal_states=[VolumeState.ERROR, VolumeState.DELETED],
-                    interval=self.get_test_wait_interval())
+                    terminal_states=[VolumeState.ERROR, VolumeState.DELETED])
 
     def test_crud_snapshot(self):
         """
@@ -119,7 +114,7 @@ class CloudBlockStoreServiceTestCase(ProviderTestBase):
             1,
             helpers.get_provider_test_data(self.provider, "placement"))
         with helpers.cleanup_action(lambda: test_vol.delete()):
-            test_vol.wait_till_ready(interval=self.get_test_wait_interval())
+            test_vol.wait_till_ready()
             snap_name = "CBSnapshot-{0}".format(name)
             test_snap = test_vol.create_snapshot(name=snap_name,
                                                  description=snap_name)
@@ -128,12 +123,10 @@ class CloudBlockStoreServiceTestCase(ProviderTestBase):
                 snap.delete()
                 snap.wait_for(
                     [SnapshotState.UNKNOWN],
-                    terminal_states=[SnapshotState.ERROR],
-                    interval=self.get_test_wait_interval())
+                    terminal_states=[SnapshotState.ERROR])
 
             with helpers.cleanup_action(lambda: cleanup_snap(test_snap)):
-                test_snap.wait_till_ready(
-                    interval=self.get_test_wait_interval())
+                test_snap.wait_till_ready()
                 self.assertTrue(
                     test_snap.id in repr(test_snap),
                     "repr(obj) should contain the object id so that the object"

+ 9 - 16
test/test_compute_service.py

@@ -27,11 +27,10 @@ class CloudComputeServiceTestCase(ProviderTestBase):
             instance.terminate()
             instance.wait_for(
                 [InstanceState.TERMINATED, InstanceState.UNKNOWN],
-                terminal_states=[InstanceState.ERROR],
-                interval=self.get_test_wait_interval())
+                terminal_states=[InstanceState.ERROR])
 
         with helpers.cleanup_action(lambda: cleanup_inst(inst)):
-            inst.wait_till_ready(interval=self.get_test_wait_interval())
+            inst.wait_till_ready()
 
             all_instances = self.provider.compute.instances.list()
 
@@ -102,10 +101,8 @@ class CloudComputeServiceTestCase(ProviderTestBase):
 
         def cleanup(inst, kp, sg):
             inst.terminate()
-            inst.wait_for(
-                [InstanceState.TERMINATED, InstanceState.UNKNOWN],
-                terminal_states=[InstanceState.ERROR],
-                interval=self.get_test_wait_interval())
+            inst.wait_for([InstanceState.TERMINATED, InstanceState.UNKNOWN],
+                          terminal_states=[InstanceState.ERROR])
             kp.delete()
             sg.delete()
 
@@ -213,7 +210,7 @@ class CloudComputeServiceTestCase(ProviderTestBase):
 #             1,
 #             helpers.get_provider_test_data(self.provider, "placement"))
 #         with helpers.cleanup_action(lambda: test_vol.delete()):
-#             test_vol.wait_till_ready(interval=self.get_test_wait_interval())
+#             test_vol.wait_till_ready()
 #             test_snap = test_vol.create_snapshot(name=name,
 #                                                  description=name)
 #
@@ -221,12 +218,10 @@ class CloudComputeServiceTestCase(ProviderTestBase):
 #                 snap.delete()
 #                 snap.wait_for(
 #                     [SnapshotState.UNKNOWN],
-#                     terminal_states=[SnapshotState.ERROR],
-#                     interval=self.get_test_wait_interval())
+#                     terminal_states=[SnapshotState.ERROR])
 #
 #             with helpers.cleanup_action(lambda: cleanup_snap(test_snap)):
-#                 test_snap.wait_till_ready(
-#                     interval=self.get_test_wait_interval())
+#                 test_snap.wait_till_ready()
 
         lc = self.provider.compute.instances.create_launch_config()
 
@@ -276,12 +271,10 @@ class CloudComputeServiceTestCase(ProviderTestBase):
             instance.terminate()
             instance.wait_for(
                 [InstanceState.TERMINATED, InstanceState.UNKNOWN],
-                terminal_states=[InstanceState.ERROR],
-                interval=self.get_test_wait_interval())
+                terminal_states=[InstanceState.ERROR])
         with helpers.cleanup_action(lambda: cleanup(inst)):
             try:
-                inst.wait_till_ready(
-                    interval=self.get_test_wait_interval())
+                inst.wait_till_ready()
             except WaitStateException as e:
                 self.fail("The block device mapped launch did not "
                           " complete successfully: %s" % e)

+ 2 - 4
test/test_image_service.py

@@ -30,12 +30,10 @@ class CloudImageServiceTestCase(ProviderTestBase):
             def cleanup_img(img):
                 img.delete()
                 img.wait_for(
-                    [MachineImageState.UNKNOWN, MachineImageState.ERROR],
-                    interval=self.get_test_wait_interval())
+                    [MachineImageState.UNKNOWN, MachineImageState.ERROR])
 
             with helpers.cleanup_action(lambda: cleanup_img(test_image)):
-                test_image.wait_till_ready(
-                    interval=self.get_test_wait_interval())
+                test_image.wait_till_ready()
 
                 self.assertTrue(
                     test_instance.id in repr(test_instance),

+ 3 - 5
test/test_object_life_cycle.py

@@ -33,13 +33,11 @@ class CloudObjectLifeCycleTestCase(ProviderTestBase):
             test_vol.wait_for([VolumeState.ERROR], timeout=10, interval=20)
 
         with helpers.cleanup_action(lambda: test_vol.delete()):
-            test_vol.wait_till_ready(interval=self.get_test_wait_interval())
+            test_vol.wait_till_ready()
             # Hitting a terminal state should raise an exception
             with self.assertRaises(WaitStateException):
-                test_vol.wait_for(
-                    [VolumeState.ERROR],
-                    terminal_states=[VolumeState.AVAILABLE],
-                    interval=self.get_test_wait_interval())
+                test_vol.wait_for([VolumeState.ERROR],
+                                  terminal_states=[VolumeState.AVAILABLE])
 
             # Hitting the timeout should raise an exception
             with self.assertRaises(WaitStateException):