Selaa lähdekoodia

Consistency fixes. Added id methods to all objects. Also made all
Resource classes inherit from Base and have eq methods.

nuwan_ag 10 vuotta sitten
vanhempi
sitoutus
c0e7eb8223

+ 106 - 6
cloudbridge/cloud/base.py

@@ -21,6 +21,7 @@ from cloudbridge.cloud.interfaces.resources import MachineImage
 from cloudbridge.cloud.interfaces.resources import MachineImageState
 from cloudbridge.cloud.interfaces.resources import ObjectLifeCycleMixin
 from cloudbridge.cloud.interfaces.resources import PageableObjectMixin
+from cloudbridge.cloud.interfaces.resources import PlacementZone
 from cloudbridge.cloud.interfaces.resources import Region
 from cloudbridge.cloud.interfaces.resources import ResultList
 from cloudbridge.cloud.interfaces.resources import SecurityGroup
@@ -228,6 +229,14 @@ class BasePageableObjectMixin(PageableObjectMixin):
 
 class BaseInstanceType(InstanceType):
 
+    def __init__(self, provider):
+        self._provider = provider
+
+    def __eq__(self, other):
+        return (isinstance(other, InstanceType) and
+                self._provider == other._provider and
+                self.id == other.id)
+
     @property
     def size_total_disk(self):
         return self.size_root_disk + self.size_ephemeral_disks
@@ -239,6 +248,22 @@ class BaseInstanceType(InstanceType):
 
 class BaseInstance(BaseObjectLifeCycleMixin, Instance):
 
+    def __init__(self, provider):
+        self._provider = provider
+
+    def __eq__(self, other):
+        return (isinstance(other, Instance) and
+                self._provider == other._provider and
+                self.id == other.id and
+                # check from most to least likely mutables
+                self.state == other.state and
+                self.name == other.name and
+                self.security_groups == other.security_groups and
+                self.public_ips == other.public_ips and
+                self.private_ips == other.private_ips and
+                self.mac_address == other.mac_address and
+                self.image_id == other.image_id)
+
     @property
     def ready_states(self):
         return [InstanceState.RUNNING]
@@ -325,6 +350,18 @@ class BaseLaunchConfig(LaunchConfig):
 
 class BaseMachineImage(BaseObjectLifeCycleMixin, MachineImage):
 
+    def __init__(self, provider):
+        self._provider = provider
+
+    def __eq__(self, other):
+        return (isinstance(other, MachineImage) and
+                self._provider == other._provider and
+                self.id == other.id and
+                # check from most to least likely mutables
+                self.state == other.state and
+                self.name == other.name and
+                self.description == other.description)
+
     @property
     def ready_states(self):
         return [MachineImageState.AVAILABLE]
@@ -340,6 +377,17 @@ class BaseMachineImage(BaseObjectLifeCycleMixin, MachineImage):
 
 class BaseVolume(BaseObjectLifeCycleMixin, Volume):
 
+    def __init__(self, provider):
+        self._provider = provider
+
+    def __eq__(self, other):
+        return (isinstance(other, Volume) and
+                self._provider == other._provider and
+                self.id == other.id and
+                # check from most to least likely mutables
+                self.state == other.state and
+                self.name == other.name)
+
     @property
     def ready_states(self):
         return [VolumeState.AVAILABLE]
@@ -355,6 +403,17 @@ class BaseVolume(BaseObjectLifeCycleMixin, Volume):
 
 class BaseSnapshot(BaseObjectLifeCycleMixin, Snapshot):
 
+    def __init__(self, provider):
+        self._provider = provider
+
+    def __eq__(self, other):
+        return (isinstance(other, Snapshot) and
+                self._provider == other._provider and
+                self.id == other.id and
+                # check from most to least likely mutables
+                self.state == other.state and
+                self.name == other.name)
+
     @property
     def ready_states(self):
         return [SnapshotState.AVAILABLE]
@@ -379,6 +438,13 @@ class BaseKeyPair(KeyPair):
             self._provider == other._provider and \
             self.name == other.name
 
+    @property
+    def id(self):
+        """
+        Return the id of this key pair.
+        """
+        return self._key_pair.name
+
     @property
     def name(self):
         """
@@ -504,24 +570,48 @@ class BaseSecurityGroupRule(SecurityGroupRule):
                                              self.group))
 
 
+class BasePlacementZone(PlacementZone):
+
+    def __init__(self, provider):
+        self._provider = provider
+
+    def __repr__(self):
+        return "<CB-{0}: {1}>".format(self.__class__.__name__,
+                                      self.id)
+
+    def __eq__(self, other):
+        return (isinstance(other, PlacementZone) and
+                self._provider == other._provider and
+                self.id == other.id)
+
+
 class BaseRegion(Region):
 
-    def __init__(self, provider, region):
+    def __init__(self, provider):
         self._provider = provider
-        self._region = region
 
     def __repr__(self):
         return "<CB-{0}: {1}>".format(self.__class__.__name__,
-                                      self.name)
+                                      self.id)
 
     def __eq__(self, other):
-        if isinstance(other, Region):
-            return self._provider == other._provider and \
-                self.id == other.id
+        return (isinstance(other, Region) and
+                self._provider == other._provider and
+                self.id == other.id)
 
 
 class BaseContainerObject(ContainerObject):
 
+    def __init__(self, provider):
+        self._provider = provider
+
+    def __eq__(self, other):
+        return (isinstance(other, ContainerObject) and
+                self._provider == other._provider and
+                self.id == other.id and
+                # check from most to least likely mutables
+                self.name == other.name)
+
     def __repr__(self):
         return "<CB-{0}: {1}>".format(self.__class__.__name__,
                                       self.name)
@@ -529,6 +619,16 @@ class BaseContainerObject(ContainerObject):
 
 class BaseContainer(BasePageableObjectMixin, Container):
 
+    def __init__(self, provider):
+        self._provider = provider
+
+    def __eq__(self, other):
+        return (isinstance(other, Container) and
+                self._provider == other._provider and
+                self.id == other.id and
+                # check from most to least likely mutables
+                self.name == other.name)
+
     def __repr__(self):
         return "<CB-{0}: {1}>".format(self.__class__.__name__,
                                       self.name)

+ 3 - 1
cloudbridge/cloud/helpers.py

@@ -12,6 +12,7 @@ def to_result_list(provider, objects, limit, marker):
     do not natively support paging, since it's somewhat inefficient.
     """
     limit = limit or provider.config.result_limit
+    total_size = len(objects)
     if marker:
         from_marker = itertools.dropwhile(
             lambda obj: not obj.id == marker, objects)
@@ -22,4 +23,5 @@ def to_result_list(provider, objects, limit, marker):
     results = list(itertools.islice(objects, limit))
     return BaseResultList(is_truncated,
                           results[-1].id if is_truncated else None,
-                          False, data=results)
+                          True, total=total_size,
+                          data=results)

+ 51 - 0
cloudbridge/cloud/interfaces/resources.py

@@ -777,6 +777,16 @@ class Snapshot(ObjectLifeCycleMixin):
         """
         pass
 
+    @abstractproperty
+    def name(self):
+        """
+        Get the snapshot name.
+
+        :rtype: ``str``
+        :return: Name for this snapshot as returned by the cloud middleware.
+        """
+        pass
+
     @abstractmethod
     def create_volume(self, placement, size=None, volume_type=None, iops=None):
         """
@@ -846,6 +856,17 @@ class KeyPair(object):
 
     __metaclass__ = ABCMeta
 
+    @abstractproperty
+    def id(self):
+        """
+        Return the id of this key pair.
+
+        :rtype: ``str``
+        :return: ID for this snapshot. Will generally correspond to the cloud
+                 middleware's name, but should be treated as an opaque value.
+        """
+        pass
+
     @abstractproperty
     def name(self):
         """
@@ -923,6 +944,16 @@ class PlacementZone(object):
     """
     __metaclass__ = ABCMeta
 
+    @abstractproperty
+    def id(self):
+        """
+        Name of the placement zone.
+
+        :rtype: str
+        :return: Name of the placement zone.
+        """
+        pass
+
     @abstractproperty
     def name(self):
         """
@@ -1210,6 +1241,16 @@ class ContainerObject(object):
     """
     __metaclass__ = ABCMeta
 
+    @abstractproperty
+    def id(self):
+        """
+        Get this object's id.
+
+        :rtype: id
+        :return: id of this object as returned by the cloud middleware.
+        """
+        pass
+
     @abstractproperty
     def name(self):
         """
@@ -1257,6 +1298,16 @@ class Container(PageableObjectMixin):
 
     __metaclass__ = ABCMeta
 
+    @abstractproperty
+    def id(self):
+        """
+        Get this container's id.
+
+        :rtype: id
+        :return: id of this container as returned by the cloud middleware.
+        """
+        pass
+
     @abstractproperty
     def name(self):
         """

+ 29 - 11
cloudbridge/cloud/providers/aws/resources.py

@@ -13,6 +13,7 @@ from cloudbridge.cloud.base import BaseInstance
 from cloudbridge.cloud.base import BaseInstanceType
 from cloudbridge.cloud.base import BaseKeyPair
 from cloudbridge.cloud.base import BaseMachineImage
+from cloudbridge.cloud.base import BasePlacementZone
 from cloudbridge.cloud.base import BaseRegion
 from cloudbridge.cloud.base import BaseSecurityGroup
 from cloudbridge.cloud.base import BaseSecurityGroupRule
@@ -20,7 +21,6 @@ from cloudbridge.cloud.base import BaseSnapshot
 from cloudbridge.cloud.base import BaseVolume
 from cloudbridge.cloud.interfaces.resources import InstanceState
 from cloudbridge.cloud.interfaces.resources import MachineImageState
-from cloudbridge.cloud.interfaces.resources import PlacementZone
 from cloudbridge.cloud.interfaces.resources import SnapshotState
 from cloudbridge.cloud.interfaces.resources import VolumeState
 
@@ -34,7 +34,7 @@ class AWSMachineImage(BaseMachineImage):
     }
 
     def __init__(self, provider, image):
-        self._provider = provider
+        super(AWSMachineImage, self).__init__(provider)
         if isinstance(image, AWSMachineImage):
             self._ec2_image = image._ec2_image
         else:
@@ -94,15 +94,25 @@ class AWSMachineImage(BaseMachineImage):
             self._ec2_image.state = "unknown"
 
 
-class AWSPlacementZone(PlacementZone):
+class AWSPlacementZone(BasePlacementZone):
 
     def __init__(self, provider, zone):
-        self._provider = provider
+        super(AWSPlacementZone, self).__init__(provider)
         if isinstance(zone, AWSPlacementZone):
             self._aws_zone = zone._aws_zone
         else:
             self._aws_zone = zone
 
+    @property
+    def id(self):
+        """
+        Get the zone id
+
+        :rtype: ``str``
+        :return: ID for this zone as returned by the cloud middleware.
+        """
+        return self._aws_zone
+
     @property
     def name(self):
         """
@@ -127,7 +137,7 @@ class AWSPlacementZone(PlacementZone):
 class AWSInstanceType(BaseInstanceType):
 
     def __init__(self, provider, instance_dict):
-        self._provider = provider
+        super(AWSInstanceType, self).__init__(provider)
         self._inst_dict = instance_dict
 
     @property
@@ -190,7 +200,7 @@ class AWSInstance(BaseInstance):
     }
 
     def __init__(self, provider, ec2_instance):
-        self._provider = provider
+        super(AWSInstance, self).__init__(provider)
         self._ec2_instance = ec2_instance
 
     @property
@@ -349,7 +359,7 @@ class AWSVolume(BaseVolume):
     }
 
     def __init__(self, provider, volume):
-        self._provider = provider
+        super(AWSVolume, self).__init__(provider)
         self._volume = volume
 
     @property
@@ -433,7 +443,7 @@ class AWSSnapshot(BaseSnapshot):
     }
 
     def __init__(self, provider, snapshot):
-        self._provider = provider
+        super(AWSSnapshot, self).__init__(provider)
         self._snapshot = snapshot
 
     @property
@@ -589,9 +599,13 @@ class AWSSecurityGroupRule(BaseSecurityGroupRule):
 class AWSContainerObject(BaseContainerObject):
 
     def __init__(self, provider, key):
-        self._provider = provider
+        super(AWSContainerObject, self).__init__(provider)
         self._key = key
 
+    @property
+    def id(self):
+        return self._key.name
+
     @property
     def name(self):
         """
@@ -626,9 +640,13 @@ class AWSContainerObject(BaseContainerObject):
 class AWSContainer(BaseContainer):
 
     def __init__(self, provider, bucket):
-        self._provider = provider
+        super(AWSContainer, self).__init__(provider)
         self._bucket = bucket
 
+    @property
+    def id(self):
+        return self._bucket.name
+
     @property
     def name(self):
         """
@@ -667,7 +685,7 @@ class AWSContainer(BaseContainer):
 class AWSRegion(BaseRegion):
 
     def __init__(self, provider, aws_region):
-        self._provider = provider
+        super(AWSRegion, self).__init__(provider)
         self._aws_region = aws_region
 
     @property

+ 6 - 6
cloudbridge/cloud/providers/aws/services.py

@@ -258,13 +258,13 @@ class AWSVolumeService(BaseVolumeService):
         """
         Creates a new volume.
         """
-        zone_name = zone.name if isinstance(zone, PlacementZone) else zone
+        zone_id = zone.id if isinstance(zone, PlacementZone) else zone
         snapshot_id = snapshot.id if isinstance(
             zone, AWSSnapshot) and snapshot else snapshot
 
         ec2_vol = self.provider.ec2_conn.create_volume(
             size,
-            zone_name,
+            zone_id,
             snapshot=snapshot_id)
         cb_vol = AWSVolume(self.provider, ec2_vol)
         cb_vol.name = name
@@ -432,9 +432,9 @@ class AWSInstanceService(BaseInstanceService):
         Creates a new virtual machine instance.
         """
         image_id = image.id if isinstance(image, MachineImage) else image
-        instance_size = instance_type.name if \
+        instance_size = instance_type.id if \
             isinstance(instance_type, InstanceType) else instance_type
-        zone_name = zone.name if isinstance(zone, PlacementZone) else zone
+        zone_id = zone.id if isinstance(zone, PlacementZone) else zone
         keypair_name = keypair.name if isinstance(
             keypair,
             KeyPair) else keypair
@@ -447,14 +447,14 @@ class AWSInstanceService(BaseInstanceService):
         else:
             security_groups_list = None
         if launch_config:
-            bdm = self._process_block_device_mappings(launch_config, zone_name)
+            bdm = self._process_block_device_mappings(launch_config, zone_id)
             net_id = self._get_net_id(launch_config)
         else:
             bdm = net_id = None
 
         reservation = self.provider.ec2_conn.run_instances(
             image_id=image_id, instance_type=instance_size,
-            min_count=1, max_count=1, placement=zone_name,
+            min_count=1, max_count=1, placement=zone_id,
             key_name=keypair_name, security_groups=security_groups_list,
             user_data=user_data, block_device_map=bdm, subnet_id=net_id)
         if reservation:

+ 28 - 10
cloudbridge/cloud/providers/openstack/resources.py

@@ -12,6 +12,7 @@ from cloudbridge.cloud.base import BaseInstance
 from cloudbridge.cloud.base import BaseInstanceType
 from cloudbridge.cloud.base import BaseKeyPair
 from cloudbridge.cloud.base import BaseMachineImage
+from cloudbridge.cloud.base import BasePlacementZone
 from cloudbridge.cloud.base import BaseRegion
 from cloudbridge.cloud.base import BaseSecurityGroup
 from cloudbridge.cloud.base import BaseSecurityGroupRule
@@ -19,7 +20,6 @@ from cloudbridge.cloud.base import BaseSnapshot
 from cloudbridge.cloud.base import BaseVolume
 from cloudbridge.cloud.interfaces.resources import InstanceState
 from cloudbridge.cloud.interfaces.resources import MachineImageState
-from cloudbridge.cloud.interfaces.resources import PlacementZone
 from cloudbridge.cloud.interfaces.resources import SnapshotState
 from cloudbridge.cloud.interfaces.resources import VolumeState
 from cloudbridge.cloud.providers.openstack import helpers as oshelpers
@@ -38,7 +38,7 @@ class OpenStackMachineImage(BaseMachineImage):
     }
 
     def __init__(self, provider, os_image):
-        self._provider = provider
+        super(OpenStackMachineImage, self).__init__(provider)
         if isinstance(os_image, OpenStackMachineImage):
             self._os_image = os_image._os_image
         else:
@@ -90,15 +90,25 @@ class OpenStackMachineImage(BaseMachineImage):
             self._os_image.status = 'unknown'
 
 
-class OpenStackPlacementZone(PlacementZone):
+class OpenStackPlacementZone(BasePlacementZone):
 
     def __init__(self, provider, zone):
-        self._provider = provider
+        super(OpenStackPlacementZone, self).__init__(provider)
         if isinstance(zone, OpenStackPlacementZone):
             self._os_zone = zone._os_zone
         else:
             self._os_zone = zone
 
+    @property
+    def id(self):
+        """
+        Get the zone id
+
+        :rtype: ``str``
+        :return: ID for this zone as returned by the cloud middleware.
+        """
+        return self._os_zone
+
     @property
     def name(self):
         """
@@ -197,7 +207,7 @@ class OpenStackInstance(BaseInstance):
     }
 
     def __init__(self, provider, os_instance):
-        self._provider = provider
+        super(OpenStackInstance, self).__init__(provider)
         self._os_instance = os_instance
 
     @property
@@ -351,7 +361,7 @@ class OpenStackInstance(BaseInstance):
 class OpenStackRegion(BaseRegion):
 
     def __init__(self, provider, os_region):
-        self._provider = provider
+        super(OpenStackRegion, self).__init__(provider)
         self._os_region = os_region
 
     @property
@@ -387,7 +397,7 @@ class OpenStackVolume(BaseVolume):
     }
 
     def __init__(self, provider, volume):
-        self._provider = provider
+        super(OpenStackVolume, self).__init__(provider)
         self._volume = volume
 
     @property
@@ -469,7 +479,7 @@ class OpenStackSnapshot(BaseSnapshot):
     }
 
     def __init__(self, provider, snapshot):
-        self._provider = provider
+        super(OpenStackSnapshot, self).__init__(provider)
         self._snapshot = snapshot
 
     @property
@@ -641,10 +651,14 @@ class OpenStackSecurityGroupRule(BaseSecurityGroupRule):
 class OpenStackContainerObject(BaseContainerObject):
 
     def __init__(self, provider, cbcontainer, obj):
-        self._provider = provider
+        super(OpenStackContainerObject, self).__init__(provider)
         self.cbcontainer = cbcontainer
         self._obj = obj
 
+    @property
+    def id(self):
+        return self._obj.get("name")
+
     @property
     def name(self):
         """
@@ -688,9 +702,13 @@ class OpenStackContainerObject(BaseContainerObject):
 class OpenStackContainer(BaseContainer):
 
     def __init__(self, provider, container):
-        self._provider = provider
+        super(OpenStackContainer, self).__init__(provider)
         self._container = container
 
+    @property
+    def id(self):
+        return self._container.get("name")
+
     @property
     def name(self):
         """

+ 4 - 4
cloudbridge/cloud/providers/openstack/services.py

@@ -329,12 +329,12 @@ class OpenStackVolumeService(BaseVolumeService):
         """
         Creates a new volume.
         """
-        zone_name = zone.name if isinstance(zone, PlacementZone) else zone
+        zone_id = zone.id if isinstance(zone, PlacementZone) else zone
         snapshot_id = snapshot.id if isinstance(
             zone, OpenStackSnapshot) and snapshot else snapshot
 
         os_vol = self.provider.cinder.volumes.create(
-            size, name=name, availability_zone=zone_name,
+            size, name=name, availability_zone=zone_id,
             snapshot_id=snapshot_id)
         return OpenStackVolume(self.provider, os_vol)
 
@@ -511,7 +511,7 @@ class OpenStackInstanceService(BaseInstanceService):
             next(
                 self.provider.compute.instance_types.find(
                     name=instance_type)).id
-        zone_name = zone.name if isinstance(zone, PlacementZone) else zone
+        zone_id = zone.id if isinstance(zone, PlacementZone) else zone
         keypair_name = keypair.name if \
             isinstance(keypair, KeyPair) else keypair
         if security_groups:
@@ -534,7 +534,7 @@ class OpenStackInstanceService(BaseInstanceService):
             instance_size,
             min_count=1,
             max_count=1,
-            availability_zone=zone_name,
+            availability_zone=zone_id,
             key_name=keypair_name,
             security_groups=security_groups_list,
             userdata=user_data,

+ 5 - 5
test/test_provider_object_store_service.py

@@ -27,13 +27,13 @@ class ProviderObjectStoreServiceTestCase(ProviderTestBase):
                 name)
 
             get_container = self.provider.object_store.get(
-                test_container.name)
+                test_container.id)
             self.assertTrue(
-                found_containers[0].name ==
-                get_container.name == test_container.name,
+                found_containers[0].id ==
+                get_container.id == test_container.id,
                 "Names returned by list: {0} and get: {1} are not as "
-                " expected: {2}" .format(found_containers[0].name,
-                                         get_container.name,
+                " expected: {2}" .format(found_containers[0].id,
+                                         get_container.id,
                                          test_container.name))
         containers = self.provider.object_store.list()
         found_containers = [c for c in containers if c.name == name]

+ 1 - 1
test/test_provider_region_service.py

@@ -20,7 +20,7 @@ class ProviderRegionServiceTestCase(ProviderTestBase):
                 Region,
                 "regions.list() should return a cloudbridge Region")
 
-        region = self.provider.compute.regions.get(regions[0].name)
+        region = self.provider.compute.regions.get(regions[0].id)
         self.assertEqual(
             region,
             regions[0],