Просмотр исходного кода

Merge branch 'master' into almahmoud-azure_full

Enis Afgan 7 лет назад
Родитель
Сommit
dfdb8daad5

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

@@ -528,6 +528,16 @@ class Instance(ObjectLifeCycleMixin, CloudResource):
         """
         pass
 
+    @abstractproperty
+    def subnet_id(self):
+        """
+        Get the subnet ID where this instance is placed.
+
+        :rtype: ``str``
+        :return: Subnet ID to which this instance is connected.
+        """
+        pass
+
 #     @abstractproperty
 #     def mac_address(self):
 #         """

+ 1 - 1
cloudbridge/cloud/providers/aws/provider.py

@@ -5,7 +5,7 @@ import os
 import boto3
 try:
     # These are installed only for the case of a dev instance
-    from moto.packages.responses import responses
+    import responses
     from moto import mock_ec2
     from moto import mock_s3
 except ImportError:

+ 9 - 2
cloudbridge/cloud/providers/aws/resources.py

@@ -268,6 +268,10 @@ class AWSInstance(BaseInstance):
     def zone_id(self):
         return self._ec2_instance.placement.get('AvailabilityZone')
 
+    @property
+    def subnet_id(self):
+        return self._ec2_instance.subnet_id
+
     @property
     def vm_firewalls(self):
         return [
@@ -760,7 +764,10 @@ class AWSBucketObject(BaseBucketObject):
 
     @property
     def size(self):
-        return self._obj.content_length
+        try:
+            return self._obj.content_length
+        except AttributeError:  # we're dealing with s3.ObjectSummary
+            return self._obj.size
 
     @property
     def last_modified(self):
@@ -830,7 +837,7 @@ class AWSBucketContainer(BaseBucketContainer):
         else:
             # pylint:disable=protected-access
             boto_objs = self.bucket._bucket.objects.all()
-        objects = [self.get(obj.key) for obj in boto_objs]
+        objects = [AWSBucketObject(self._provider, obj) for obj in boto_objs]
         return ClientPagedResultList(self._provider, objects,
                                      limit=limit, marker=marker)
 

+ 15 - 1
cloudbridge/cloud/providers/azure/resources.py

@@ -1298,7 +1298,7 @@ class AzureInstance(BaseInstance):
     @property
     def image_id(self):
         """
-        Get the image ID for this insance.
+        Get the image ID for this instance.
         """
         return self._vm.storage_profile.image_reference.id
 
@@ -1309,6 +1309,20 @@ class AzureInstance(BaseInstance):
         """
         return self._vm.location
 
+    @property
+    def subnet_id(self):
+        """
+        Return the first subnet id associated with the first network iface.
+
+        An Azure instance can have multiple network interfaces attached with
+        each interface having at most one subnet. This method will return only
+        the subnet of the first attached network interface.
+        """
+        for nic_id in self._nic_ids:
+            nic = self._provider.azure_client.get_nic(nic_id)
+            for ipc in nic.ip_configurations:
+                return ipc.subnet.id
+
     @property
     def vm_firewalls(self):
         return [self._provider.security.vm_firewalls.get(group_id)

+ 29 - 0
cloudbridge/cloud/providers/openstack/resources.py

@@ -366,6 +366,35 @@ class OpenStackInstance(BaseInstance):
         """
         return getattr(self._os_instance, 'OS-EXT-AZ:availability_zone', None)
 
+    @property
+    def subnet_id(self):
+        """
+        Extract (one) subnet id associated with this instance.
+
+        In OpenStack, instances are associated with ports instead of
+        instances so we need to dig through several connections to retrieve
+        the subnet_id. Further, there can potentially be several ports
+        connected to to different subnets. This implementation retrieves one
+        subnet, the one corresponding to port associated with the first
+        private IP associated with the instance.
+        """
+        # MAC address can be used to identify a port so extract the MAC
+        # address corresponding to the (first) private IP associated with the
+        # instance.
+        for net in self._os_instance.to_dict().get('addresses').keys():
+            for iface in self._os_instance.to_dict().get('addresses')[net]:
+                if iface.get('OS-EXT-IPS:type') == 'fixed':
+                    port = iface.get('OS-EXT-IPS-MAC:mac_addr')
+                    addr = iface.get('addr')
+                    break
+        # Now get a handle to a port with the given MAC address and get the
+        # subnet to which the private IP is connected as the desired id.
+        for prt in self._provider.neutron.list_ports().get('ports'):
+            if prt.get('mac_address') == port:
+                for ip in prt.get('fixed_ips'):
+                    if ip.get('ip_address') == addr:
+                        return ip.get('subnet_id')
+
     @property
     def vm_firewalls(self):
         return [

+ 1 - 1
setup.py

@@ -48,7 +48,7 @@ REQS_FULL = REQS_BASE + REQS_AWS + REQS_AZURE + REQS_OPENSTACK
 REQS_DEV = ([
     'tox>=2.1.1',
     'nose',
-    'moto>=1.1.11',  # until https://github.com/spulec/moto/issues/1396
+    'moto>=1.3.2',
     'sphinx>=1.3.1',
     'pydevd',
     'flake8>=3.3.0',

+ 7 - 0
test/test_object_store_service.py

@@ -110,6 +110,13 @@ class CloudObjectStoreServiceTestCase(ProviderTestBase):
                     isinstance(objs[0].size, int),
                     "Object size property needs to be a int, not {0}".format(
                         type(objs[0].size)))
+                # GET an object as the size property implementation differs
+                # for objects returned by LIST and GET.
+                obj = test_bucket.objects.get(objs[0].id)
+                self.assertTrue(
+                    isinstance(objs[0].size, int),
+                    "Object size property needs to be an int, not {0}".format(
+                        type(obj.size)))
                 self.assertTrue(
                     datetime.strptime(objs[0].last_modified[:23],
                                       "%Y-%m-%dT%H:%M:%S.%f"),