Ver código fonte

Merge pull request #259 from nuwang/add_provider_clone

Added support for cloning providers in different zones
Enis Afgan 5 anos atrás
pai
commit
8c132d6de2

+ 8 - 0
cloudbridge/base/provider.py

@@ -147,6 +147,14 @@ class BaseCloudProvider(CloudProvider):
             raise ProviderConnectionException(
                 "Authentication with cloud provider failed: %s" % (e,))
 
+    def clone(self, zone=None):
+        cloned_config = self.config.copy()
+        cloned_provider = self.__class__(cloned_config)
+        if zone:
+            # pylint:disable=protected-access
+            cloned_provider._zone_name = zone.name
+        return cloned_provider
+
     def _deepgetattr(self, obj, attr):
         """Recurses through an attribute chain to get the ultimate value."""
         return functools.reduce(getattr, attr.split('.'), obj)

+ 29 - 0
cloudbridge/interfaces/provider.py

@@ -71,6 +71,35 @@ class CloudProvider(object):
         """
         pass
 
+    @abstractmethod
+    def clone(self, zone=None):
+        """
+        Create a clone of this provider. An optional `zone` parameter can be
+        used to clone the provider to use a different zone.
+        As each cloudbridge provider is restricted to a particular zone,
+        this is useful when performing cross-zonal operations.
+
+        Example:
+
+        .. code-block:: python
+
+            # list instances in all availability zones
+            all_instances = []
+            for zone in provider.compute.regions.current.zones:
+                new_provider = provider.clone(zone=zone)
+                all_instances.append(list(new_provider.compute.instances))
+            print(all_instances)
+
+        :param zone: Changes the provider's zone to the requested
+                     AvailabilityZone
+        :type zone: :class:`.PlacementZone` object
+
+        :rtype: :class:`.CloudProvider`
+        :return:  A clone of the CloudProvider, with zone changed to the
+                  requested zone.
+        """
+        pass
+
     @abstractmethod
     def authenticate(self):
         """

+ 13 - 0
tests/test_interface.py

@@ -2,10 +2,12 @@ import unittest
 
 import cloudbridge
 from cloudbridge import interfaces
+from cloudbridge.base import helpers as cb_helpers
 from cloudbridge.factory import CloudProviderFactory
 from cloudbridge.interfaces import TestMockHelperMixin
 from cloudbridge.interfaces.exceptions import ProviderConnectionException
 
+from tests import helpers
 from tests.helpers import ProviderTestBase
 
 
@@ -93,3 +95,14 @@ class CloudInterfaceTestCase(ProviderTestBase):
         # FIXME: GCP always requires a zone, so skip for now
         if self.provider.PROVIDER_ID != 'gcp':
             self.assertIsNotNone(cloned_provider.zone_name)
+
+    def test_clone_provider_zone(self):
+        for zone in list(self.provider.compute.regions.current.zones)[:2]:
+            cloned_provider = self.provider.clone(zone=zone)
+            test_vol = None
+            # Currently, volumes are the cheapest object that's actually
+            # cross-zonal for all providers
+            with cb_helpers.cleanup_action(lambda: test_vol.delete()):
+                label = "cb-attachvol-{0}".format(helpers.get_uuid())
+                test_vol = cloned_provider.storage.volumes.create(label, 1)
+                self.assertEqual(test_vol.zone_id, zone.id)