浏览代码

Merge branch 'master' of github.com:gvlproject/cloudbridge

Enis Afgan 10 年之前
父节点
当前提交
304a734cbb

+ 23 - 0
cloudbridge/providers/aws/resources.py

@@ -11,6 +11,7 @@ from cloudbridge.providers.base import BaseInstance
 from cloudbridge.providers.base import BaseInstanceType
 from cloudbridge.providers.base import BaseInstanceType
 from cloudbridge.providers.base import BaseKeyPair
 from cloudbridge.providers.base import BaseKeyPair
 from cloudbridge.providers.base import BaseMachineImage
 from cloudbridge.providers.base import BaseMachineImage
+from cloudbridge.providers.base import BaseRegion
 from cloudbridge.providers.base import BaseSecurityGroup
 from cloudbridge.providers.base import BaseSecurityGroup
 from cloudbridge.providers.base import BaseSecurityGroupRule
 from cloudbridge.providers.base import BaseSecurityGroupRule
 from cloudbridge.providers.base import BaseSnapshot
 from cloudbridge.providers.base import BaseSnapshot
@@ -656,3 +657,25 @@ class AWSContainer(Container):
 
 
     def __repr__(self):
     def __repr__(self):
         return "<CB-AWSContainer: {0}>".format(self.name)
         return "<CB-AWSContainer: {0}>".format(self.name)
+
+
+class AWSRegion(BaseRegion):
+
+    def __init__(self, provider, aws_region):
+        self._provider = provider
+        self._aws_region = aws_region
+
+    @property
+    def id(self):
+        return self._aws_region.name
+
+    @property
+    def name(self):
+        return self._aws_region.name
+
+    @property
+    def zones(self):
+        """
+        Accesss information about placement zones within this region.
+        """
+        pass

+ 26 - 10
cloudbridge/providers/aws/services.py

@@ -11,6 +11,7 @@ from cloudbridge.providers.base import BaseInstanceService
 from cloudbridge.providers.base import BaseInstanceTypesService
 from cloudbridge.providers.base import BaseInstanceTypesService
 from cloudbridge.providers.base import BaseKeyPairService
 from cloudbridge.providers.base import BaseKeyPairService
 from cloudbridge.providers.base import BaseObjectStoreService
 from cloudbridge.providers.base import BaseObjectStoreService
+from cloudbridge.providers.base import BaseRegionService
 from cloudbridge.providers.base import BaseSecurityGroupService
 from cloudbridge.providers.base import BaseSecurityGroupService
 from cloudbridge.providers.base import BaseSecurityService
 from cloudbridge.providers.base import BaseSecurityService
 from cloudbridge.providers.base import BaseSnapshotService
 from cloudbridge.providers.base import BaseSnapshotService
@@ -26,6 +27,7 @@ from .resources import AWSInstance
 from .resources import AWSInstanceType
 from .resources import AWSInstanceType
 from .resources import AWSKeyPair
 from .resources import AWSKeyPair
 from .resources import AWSMachineImage
 from .resources import AWSMachineImage
+from .resources import AWSRegion
 from .resources import AWSSecurityGroup
 from .resources import AWSSecurityGroup
 from .resources import AWSSnapshot
 from .resources import AWSSnapshot
 from .resources import AWSVolume
 from .resources import AWSVolume
@@ -381,6 +383,7 @@ class AWSComputeService(BaseComputeService):
         super(AWSComputeService, self).__init__(provider)
         super(AWSComputeService, self).__init__(provider)
         self._instance_type_svc = AWSInstanceTypesService(self.provider)
         self._instance_type_svc = AWSInstanceTypesService(self.provider)
         self._instance_svc = AWSInstanceService(self.provider)
         self._instance_svc = AWSInstanceService(self.provider)
+        self._region_svc = AWSRegionService(self.provider)
 
 
     @property
     @property
     def instance_types(self):
     def instance_types(self):
@@ -390,15 +393,9 @@ class AWSComputeService(BaseComputeService):
     def instances(self):
     def instances(self):
         return self._instance_svc
         return self._instance_svc
 
 
-    def list_regions(self):
-        """
-        List all data center regions for this provider.
-
-        :rtype: ``list`` of :class:`.Region`
-        :return: list of Region objects
-        """
-        raise NotImplementedError(
-            'list_regions not implemented by this provider')
+    @property
+    def regions(self):
+        return self._region_svc
 
 
 
 
 class AWSInstanceService(BaseInstanceService):
 class AWSInstanceService(BaseInstanceService):
@@ -483,7 +480,7 @@ class AWSInstanceTypesService(BaseInstanceTypesService):
     @property
     @property
     def instance_data(self):
     def instance_data(self):
         """
         """
-        TODO: Neeeds a caching function with timeout
+        TODO: Needs a caching function with timeout
         """
         """
         r = requests.get(self.provider.config.get(
         r = requests.get(self.provider.config.get(
             "aws_instance_info_url", AWS_INSTANCE_DATA_DEFAULT_URL))
             "aws_instance_info_url", AWS_INSTANCE_DATA_DEFAULT_URL))
@@ -496,3 +493,22 @@ class AWSInstanceTypesService(BaseInstanceTypesService):
     def find_by_name(self, name):
     def find_by_name(self, name):
         return next(
         return next(
             (itype for itype in self.list() if itype.name == name), None)
             (itype for itype in self.list() if itype.name == name), None)
+
+
+class AWSRegionService(BaseRegionService):
+
+    def __init__(self, provider):
+        super(AWSRegionService, self).__init__(provider)
+
+    def get(self, region_id):
+        region = self.provider.ec2_conn.get_all_regions(
+            region_names=[region_id])
+        if region:
+            return AWSRegion(self.provider, region[0])
+        else:
+            return None
+
+    def list(self):
+        regions = self.provider.ec2_conn.get_all_regions()
+        return [AWSRegion(self.provider, region)
+                for region in regions]

+ 29 - 5
cloudbridge/providers/base.py

@@ -13,6 +13,7 @@ from cloudbridge.providers.interfaces import KeyPair
 from cloudbridge.providers.interfaces import MachineImage
 from cloudbridge.providers.interfaces import MachineImage
 from cloudbridge.providers.interfaces import MachineImageState
 from cloudbridge.providers.interfaces import MachineImageState
 from cloudbridge.providers.interfaces import ObjectLifeCycleMixin
 from cloudbridge.providers.interfaces import ObjectLifeCycleMixin
+from cloudbridge.providers.interfaces import Region
 from cloudbridge.providers.interfaces import SecurityGroup
 from cloudbridge.providers.interfaces import SecurityGroup
 from cloudbridge.providers.interfaces import SecurityGroupRule
 from cloudbridge.providers.interfaces import SecurityGroupRule
 from cloudbridge.providers.interfaces import Snapshot
 from cloudbridge.providers.interfaces import Snapshot
@@ -20,16 +21,17 @@ from cloudbridge.providers.interfaces import SnapshotState
 from cloudbridge.providers.interfaces import Volume
 from cloudbridge.providers.interfaces import Volume
 from cloudbridge.providers.interfaces import VolumeState
 from cloudbridge.providers.interfaces import VolumeState
 from cloudbridge.providers.interfaces import WaitStateException
 from cloudbridge.providers.interfaces import WaitStateException
-from cloudbridge.providers.interfaces.services import InstanceTypesService
-from cloudbridge.providers.interfaces.services import KeyPairService
-from cloudbridge.providers.interfaces.services import ObjectStoreService
-from cloudbridge.providers.interfaces.services import SecurityGroupService
-from cloudbridge.providers.interfaces.services import SecurityService
 from cloudbridge.providers.interfaces.services import BlockStoreService
 from cloudbridge.providers.interfaces.services import BlockStoreService
 from cloudbridge.providers.interfaces.services import ComputeService
 from cloudbridge.providers.interfaces.services import ComputeService
 from cloudbridge.providers.interfaces.services import ImageService
 from cloudbridge.providers.interfaces.services import ImageService
 from cloudbridge.providers.interfaces.services import InstanceService
 from cloudbridge.providers.interfaces.services import InstanceService
+from cloudbridge.providers.interfaces.services import InstanceTypesService
+from cloudbridge.providers.interfaces.services import KeyPairService
+from cloudbridge.providers.interfaces.services import ObjectStoreService
 from cloudbridge.providers.interfaces.services import ProviderService
 from cloudbridge.providers.interfaces.services import ProviderService
+from cloudbridge.providers.interfaces.services import RegionService
+from cloudbridge.providers.interfaces.services import SecurityGroupService
+from cloudbridge.providers.interfaces.services import SecurityService
 from cloudbridge.providers.interfaces.services import SnapshotService
 from cloudbridge.providers.interfaces.services import SnapshotService
 from cloudbridge.providers.interfaces.services import VolumeService
 from cloudbridge.providers.interfaces.services import VolumeService
 
 
@@ -289,6 +291,22 @@ class BaseSecurityGroupRule(SecurityGroupRule):
             self.ip_protocol, self.from_port, self.to_port)
             self.ip_protocol, self.from_port, self.to_port)
 
 
 
 
+class BaseRegion(Region):
+
+    def __init__(self, provider, region):
+        self._provider = provider
+        self._region = region
+
+    def __repr__(self):
+        return "<CB-{0}: {1}>".format(self.__class__.__name__,
+                                      self.name)
+
+    def __eq__(self, other):
+        if isinstance(other, Region):
+            return self._provider == other._provider and \
+                self.id == other.id
+
+
 class BaseProviderService(ProviderService):
 class BaseProviderService(ProviderService):
 
 
     def __init__(self, provider):
     def __init__(self, provider):
@@ -363,3 +381,9 @@ class BaseInstanceService(InstanceService, BaseProviderService):
 
 
     def __init__(self, provider):
     def __init__(self, provider):
         super(BaseInstanceService, self).__init__(provider)
         super(BaseInstanceService, self).__init__(provider)
+
+
+class BaseRegionService(RegionService, BaseProviderService):
+
+    def __init__(self, provider):
+        super(BaseRegionService, self).__init__(provider)

+ 1 - 0
cloudbridge/providers/interfaces/__init__.py

@@ -28,6 +28,7 @@ from .services import InstanceTypesService
 from .services import KeyPairService
 from .services import KeyPairService
 from .services import ObjectStoreService
 from .services import ObjectStoreService
 from .services import ProviderService
 from .services import ProviderService
+from .services import RegionService
 from .services import SecurityGroupService
 from .services import SecurityGroupService
 from .services import SecurityService
 from .services import SecurityService
 from .services import SnapshotService
 from .services import SnapshotService

+ 15 - 5
cloudbridge/providers/interfaces/resources.py

@@ -556,6 +556,16 @@ class Region(object):
     """
     """
     __metaclass__ = ABCMeta
     __metaclass__ = ABCMeta
 
 
+    @abstractproperty
+    def id(self):
+        """
+        The id for this region
+
+        :rtype: str
+        :return: Id of the region.
+        """
+        pass
+
     @abstractproperty
     @abstractproperty
     def name(self):
     def name(self):
         """
         """
@@ -566,13 +576,13 @@ class Region(object):
         """
         """
         pass
         pass
 
 
-    @abstractmethod
-    def list_zones(self):
+    @abstractproperty
+    def zones(self):
         """
         """
-        List all available placement zones within this region.
+        Accesss information about placement zones within this region.
 
 
-        :rtype: list
-        :return: List of all the available placement zones.
+        :rtype: iterable
+        :return: Iterable of  available placement zones in this region.
         """
         """
         pass
         pass
 
 

+ 34 - 5
cloudbridge/providers/interfaces/services.py

@@ -49,13 +49,13 @@ class ComputeService(ProviderService):
         """
         """
         pass
         pass
 
 
-    @abstractmethod
-    def list_regions(self):
+    @abstractproperty
+    def regions(self):
         """
         """
-        List all data center regions for this provider.
+        Provides access to all Region related services in this provider.
 
 
-        :rtype: ``list`` of :class:`.Region`
-        :return: list of Region objects
+        :rtype: ``object`` of :class:`.RegionService`
+        :return:  a RegionService object
         """
         """
         pass
         pass
 
 
@@ -570,3 +570,32 @@ class InstanceTypesService(object):
         :return: an Instance object
         :return: an Instance object
         """
         """
         pass
         pass
+
+
+class RegionService(ProviderService):
+
+    """
+    Base interface for a Region service
+    """
+    __metaclass__ = ABCMeta
+
+    @abstractmethod
+    def get(self, region_id):
+        """
+        Returns a region given its id. Returns None if the region
+        does not exist.
+
+        :rtype: ``object`` of :class:`.Region`
+        :return:  a Region instance
+        """
+        pass
+
+    @abstractmethod
+    def list(self):
+        """
+        List all regions.
+
+        :rtype: ``list`` of :class:`.Region`
+        :return:  list of region objects
+        """
+        pass

+ 12 - 5
cloudbridge/providers/openstack/resources.py

@@ -10,6 +10,7 @@ from cloudbridge.providers.base import BaseInstance
 from cloudbridge.providers.base import BaseInstanceType
 from cloudbridge.providers.base import BaseInstanceType
 from cloudbridge.providers.base import BaseKeyPair
 from cloudbridge.providers.base import BaseKeyPair
 from cloudbridge.providers.base import BaseMachineImage
 from cloudbridge.providers.base import BaseMachineImage
+from cloudbridge.providers.base import BaseRegion
 from cloudbridge.providers.base import BaseSecurityGroup
 from cloudbridge.providers.base import BaseSecurityGroup
 from cloudbridge.providers.base import BaseSecurityGroupRule
 from cloudbridge.providers.base import BaseSecurityGroupRule
 from cloudbridge.providers.base import BaseSnapshot
 from cloudbridge.providers.base import BaseSnapshot
@@ -19,7 +20,6 @@ from cloudbridge.providers.interfaces import ContainerObject
 from cloudbridge.providers.interfaces import InstanceState
 from cloudbridge.providers.interfaces import InstanceState
 from cloudbridge.providers.interfaces import MachineImageState
 from cloudbridge.providers.interfaces import MachineImageState
 from cloudbridge.providers.interfaces import PlacementZone
 from cloudbridge.providers.interfaces import PlacementZone
-from cloudbridge.providers.interfaces import Region
 from cloudbridge.providers.interfaces import SnapshotState
 from cloudbridge.providers.interfaces import SnapshotState
 from cloudbridge.providers.interfaces import VolumeState
 from cloudbridge.providers.interfaces import VolumeState
 
 
@@ -333,18 +333,25 @@ class OpenStackInstance(BaseInstance):
         return "<CB-OSInstance: {0} ({1})>".format(self.name, self.instance_id)
         return "<CB-OSInstance: {0} ({1})>".format(self.name, self.instance_id)
 
 
 
 
-class OpenStackRegion(Region):
+class OpenStackRegion(BaseRegion):
 
 
     def __init__(self, provider, os_region):
     def __init__(self, provider, os_region):
         self._provider = provider
         self._provider = provider
         self._os_region = os_region
         self._os_region = os_region
 
 
+    @property
+    def id(self):
+        return self._os_region
+
     @property
     @property
     def name(self):
     def name(self):
-        return self._os_region.zoneName
+        return self._os_region
 
 
-    def __repr__(self):
-        return "<CB-OSRegion: {0}>".format(self.name)
+    @property
+    def zones(self):
+        # detailed must be set to ``False`` because the (default) ``True``
+        # value requires Admin privileges
+        return self._provider.nova.availability_zones.list(detailed=False)
 
 
 
 
 class OpenStackVolume(BaseVolume):
 class OpenStackVolume(BaseVolume):

+ 30 - 8
cloudbridge/providers/openstack/services.py

@@ -11,6 +11,7 @@ from cloudbridge.providers.base import BaseInstanceService
 from cloudbridge.providers.base import BaseInstanceTypesService
 from cloudbridge.providers.base import BaseInstanceTypesService
 from cloudbridge.providers.base import BaseKeyPairService
 from cloudbridge.providers.base import BaseKeyPairService
 from cloudbridge.providers.base import BaseObjectStoreService
 from cloudbridge.providers.base import BaseObjectStoreService
+from cloudbridge.providers.base import BaseRegionService
 from cloudbridge.providers.base import BaseSecurityGroupService
 from cloudbridge.providers.base import BaseSecurityGroupService
 from cloudbridge.providers.base import BaseSecurityService
 from cloudbridge.providers.base import BaseSecurityService
 from cloudbridge.providers.base import BaseSnapshotService
 from cloudbridge.providers.base import BaseSnapshotService
@@ -388,12 +389,38 @@ class OpenStackObjectStoreService(BaseObjectStoreService):
         return self.get(name)
         return self.get(name)
 
 
 
 
+class OpenStackRegionService(BaseRegionService):
+
+    def __init__(self, provider):
+        super(OpenStackRegionService, self).__init__(provider)
+
+    def get(self, region_id):
+        regions = [endpoint.get('region') or endpoint.get('region_id')
+                   for svc in self.provider.keystone.service_catalog.get_data()
+                   for endpoint in svc.get('endpoints', [])]
+        region = [region for region in regions
+                  if region == region_id]
+        if region:
+            return OpenStackRegion(self.provider, region[0])
+        else:
+            return None
+
+    def list(self):
+        regions = [endpoint.get('region') or endpoint.get('region_id')
+                   for svc in self.provider.keystone.service_catalog.get_data()
+                   for endpoint in svc.get('endpoints', [])]
+        regions = [region for region in regions if region]
+        return [OpenStackRegion(self.provider, region)
+                for region in regions]
+
+
 class OpenStackComputeService(BaseComputeService):
 class OpenStackComputeService(BaseComputeService):
 
 
     def __init__(self, provider):
     def __init__(self, provider):
         super(OpenStackComputeService, self).__init__(provider)
         super(OpenStackComputeService, self).__init__(provider)
         self._instance_type_svc = OpenStackInstanceTypesService(self._provider)
         self._instance_type_svc = OpenStackInstanceTypesService(self._provider)
         self._instance_svc = OpenStackInstanceService(self._provider)
         self._instance_svc = OpenStackInstanceService(self._provider)
+        self._region_svc = OpenStackRegionService(self.provider)
 
 
     @property
     @property
     def instance_types(self):
     def instance_types(self):
@@ -403,14 +430,9 @@ class OpenStackComputeService(BaseComputeService):
     def instances(self):
     def instances(self):
         return self._instance_svc
         return self._instance_svc
 
 
-    def list_regions(self):
-        """
-        List all data center regions.
-        """
-        # detailed must be set to ``False`` because the (default) ``True``
-        # value requires Admin priviledges
-        regions = self._provider.nova.availability_zones.list(detailed=False)
-        return [OpenStackRegion(self._provider, region) for region in regions]
+    @property
+    def regions(self):
+        return self._region_svc
 
 
 
 
 class OpenStackInstanceService(BaseInstanceService):
 class OpenStackInstanceService(BaseInstanceService):

+ 2 - 0
test/__init__.py

@@ -36,6 +36,7 @@ from test.test_provider_image_service import ProviderImageServiceTestCase
 from test.test_provider_interface import ProviderInterfaceTestCase
 from test.test_provider_interface import ProviderInterfaceTestCase
 from test.test_provider_object_store_service import \
 from test.test_provider_object_store_service import \
     ProviderObjectStoreServiceTestCase
     ProviderObjectStoreServiceTestCase
+from test.test_provider_region_service import ProviderRegionServiceTestCase
 from test.test_provider_security_service import ProviderSecurityServiceTestCase
 from test.test_provider_security_service import ProviderSecurityServiceTestCase
 
 
 
 
@@ -44,6 +45,7 @@ PROVIDER_TESTS = [
     ProviderSecurityServiceTestCase,
     ProviderSecurityServiceTestCase,
     ProviderInstanceTypesServiceTestCase,
     ProviderInstanceTypesServiceTestCase,
     ProviderComputeServiceTestCase,
     ProviderComputeServiceTestCase,
+    ProviderRegionServiceTestCase,
     ProviderImageServiceTestCase,
     ProviderImageServiceTestCase,
     ProviderBlockStoreServiceTestCase,
     ProviderBlockStoreServiceTestCase,
     ProviderObjectStoreServiceTestCase
     ProviderObjectStoreServiceTestCase

+ 2 - 2
test/test_provider_object_store_service.py

@@ -93,13 +93,13 @@ class ProviderObjectStoreServiceTestCase(ProviderTestBase):
             obj = test_container.create_object(obj_name)
             obj = test_container.create_object(obj_name)
 
 
             with helpers.exception_action(lambda: obj.delete()):
             with helpers.exception_action(lambda: obj.delete()):
-                content = "Hello World. Here's some content"
+                content = b"Hello World. Here's some content"
                 # TODO: Upload and download methods accept different parameter
                 # TODO: Upload and download methods accept different parameter
                 # types. Need to make this consistent - possibly provider
                 # types. Need to make this consistent - possibly provider
                 # multiple methods like upload_from_file, from_stream etc.
                 # multiple methods like upload_from_file, from_stream etc.
                 obj.upload(content)
                 obj.upload(content)
                 target_stream = BytesIO()
                 target_stream = BytesIO()
                 obj.download(target_stream)
                 obj.download(target_stream)
-                self.assertEqual(str(target_stream.getvalue()), content)
+                self.assertEqual(target_stream.getvalue(), content)
                 obj.delete()
                 obj.delete()
             test_container.delete()
             test_container.delete()

+ 27 - 0
test/test_provider_region_service.py

@@ -0,0 +1,27 @@
+from cloudbridge.providers.interfaces import Region
+from test.helpers import ProviderTestBase
+
+
+class ProviderRegionServiceTestCase(ProviderTestBase):
+
+    def __init__(self, methodName, provider):
+        super(ProviderRegionServiceTestCase, self).__init__(
+            methodName=methodName, provider=provider)
+
+    def test_get_and_list_regions(self):
+        """
+        Test whether the region listing methods work,
+        and whether zones are returned appropriately.
+        """
+        regions = self.provider.compute.regions.list()
+        for region in regions:
+            self.assertIsInstance(
+                region,
+                Region,
+                "regions.list() should return a cloudbridge Region")
+
+        region = self.provider.compute.regions.get(regions[0].name)
+        self.assertEqual(
+            region,
+            regions[0],
+            "List and get methods should return the same regions")