Преглед изворни кода

Updated find methods with new filter method
Implemented unit test for volume internal methods
Updated mock azure client and fixed the failure tests

vikramdoda пре 9 година
родитељ
комит
a8923b0c98

+ 53 - 27
cloudbridge/cloud/providers/azure/azure_client.py

@@ -1,4 +1,5 @@
 import logging
+from io import BytesIO
 
 from azure.common.credentials import ServicePrincipalCredentials
 from azure.mgmt.compute import ComputeManagementClient
@@ -77,11 +78,7 @@ class AzureClient(object):
     def list_locations(self):
         return self.subscription_client.subscriptions.list_locations(self.subscription_id)
 
-    def list_security_group(self, filters=None):
-        # security_groups = FilterList(
-        #     self.network_management_client.network_security_groups.list(self.resource_group_name))
-        # security_groups.filter(filters)
-        # return security_groups
+    def list_security_group(self):
         return self.network_management_client.network_security_groups.list(self.resource_group_name)
 
     def create_security_group(self, name, parameters):
@@ -107,10 +104,8 @@ class AzureClient(object):
     def delete_security_group(self, name):
         return self.network_management_client.network_security_groups.delete(self.resource_group_name, name)
 
-    def list_containers(self, filters=None):
-        containers = FilterList(self.blob_service.list_containers())
-        containers.filter(filters)
-        return containers
+    def list_containers(self):
+        return self.blob_service.list_containers()
 
     def create_container(self, container_name):
         self.blob_service.create_container(container_name, public_access=PublicAccess.Container)
@@ -144,7 +139,9 @@ class AzureClient(object):
         return self.blob_service.make_blob_url(container_name, blob_name)
 
     def get_blob_content(self, container_name, blob_name):
-        return self.blob_service.get_blob_to_text(container_name, blob_name)
+        stream = BytesIO()
+        self.blob_service.get_blob_to_stream(container_name, blob_name, stream=stream)
+        return stream
 
     def create_empty_disk(self, disk_name, size, region=None, snapshot_id=None):
         if snapshot_id:
@@ -159,10 +156,10 @@ class AzureClient(object):
                 'creation_data': {
                     'create_option': 'empty'
                 }
-            }
+            },
+            raw=True
         )
-        disk_resource = async_creation.result()
-        return disk_resource
+        return async_creation
 
     def create_snapshot_disk(self, disk_name, snapshot_id, region=None):
         async_creation = self.compute_client.disks.create_or_update(
@@ -185,18 +182,47 @@ class AzureClient(object):
     def list_disks(self):
         return self.compute_client.disks.list()
 
+    def delete_disk(self, disk_name):
+        async_deletion = self.compute_client.disks.delete(self.resource_group_name, disk_name)
+        async_deletion.wait()
+
+    def attach_disk(self, vm_name, disk_name, disk_id):
+        vm = self.compute_client.virtual_machines.get(
+            self.resource_group_name,
+            vm_name
+        )
+
+        if vm:
+            vm.storage_profile.data_disks.append({
+                'lun': len(vm.storage_profile.data_disks),  # You choose the value, depending of what is available for you
+                'name': disk_name,
+                'create_option': 'attach',
+                'managed_disk': {
+                    'id': disk_id
+                }
+            })
+            async_update = self.compute_client.virtual_machines.create_or_update(
+                self.resource_group_name,
+                vm.name,
+                vm,
+            )
+            async_update.wait()
+        return None
 
-# TODO: find out a better way.
-class FilterList(list):
-    def filter(self, filters):
-        filtered_list = []
-        if filters:
-            for obj in self:
-                for key in filters:
-                    print('original value ' + str(getattr(obj, key)) + ' key value ' + filters[key])
-                    if filters[key] not in str(getattr(obj, key)):
-                        print("removing " + str(getattr(obj, key)))
-                        filtered_list.append(obj)
-                        # self.remove(obj)
-            for s in filtered_list:
-                self.remove(s)
+    def detach_disk(self, disk_id):
+        virtual_machine = None
+        for index, vm in enumerate(self.compute_client.virtual_machines.list_all()):
+            for index, item in enumerate(vm.storage_profile.data_disks):
+                if item.managed_disk and item.managed_disk.id == disk_id:
+                    vm.storage_profile.data_disks.remove(item)
+                    virtual_machine = vm
+                break
+
+        if virtual_machine:
+            async_update = self.compute_client.virtual_machines.create_or_update(
+                self.resource_group_name,
+                virtual_machine.name,
+                virtual_machine
+            )
+            async_update.wait()
+        return None

+ 21 - 0
cloudbridge/cloud/providers/azure/helpers.py

@@ -0,0 +1,21 @@
+def filter(list_items, filters):
+    filtered_list = []
+    if filters:
+        for obj in list_items:
+            for key in filters:
+                if filters[key] in str(getattr(obj, key)):
+                    filtered_list.append(obj)
+    return filtered_list
+
+
+def parse_url(template_url, original_url):
+    template_url_parts = template_url.split('/')
+    original_url_parts = original_url.split('/')
+    if len(template_url_parts) != len(original_url_parts):
+        raise Exception('Invalid url parameter passed')
+    d = {}
+    for k, v in zip(template_url_parts, original_url_parts):
+        if k.startswith('{') and k.endswith('}'):
+            d.update({k[1:-1]: v})
+
+    return d

+ 34 - 15
cloudbridge/cloud/providers/azure/mock_azure_client.py

@@ -1,10 +1,12 @@
+from io import StringIO
+
 from azure.mgmt.compute.models import Disk, CreationData, DiskCreateOption
 from azure.mgmt.network.models import NetworkSecurityGroup
 from azure.mgmt.network.models import SecurityRule
 from azure.mgmt.resource.resources.models import ResourceGroup
 from azure.storage.blob.models import Container, Blob
 
-from cloudbridge.cloud.providers.azure.azure_client import FilterList
+from cloudbridge.cloud.providers.azure import helpers as azure_helpers
 
 
 class MockAzureClient:
@@ -57,13 +59,14 @@ class MockAzureClient:
 
     block2 = Blob()
     block2.name = "block2"
-    block2.content = "blob2Content"
+    block2.content ="blob2Content"
 
     block3 = Blob()
     block3.name = "block3"
     block3.content = None
 
-    blocks = [block1, block2, block3]
+    blocks = {'container1':[block1, block2, block3],
+              'container2':[block1, block2, block3]}
 
     rg = ResourceGroup(location='westus')
     rg.name = "testResourceGroup"
@@ -98,8 +101,7 @@ class MockAzureClient:
         self.security_groups.append(sg_create)
         return sg_create
 
-    def list_security_group(self, filters=None):
-
+    def list_security_group(self):
         return self.security_groups
 
     def delete_security_group(self, name):
@@ -143,14 +145,13 @@ class MockAzureClient:
                 return container
         return None
 
-    def list_containers(self, filters=None):
-        containers = FilterList(self.containers)
-        containers.filter(filters)
-        return containers
+    def list_containers(self):
+        return self.containers
 
     def create_container(self, container_name):
         new_container = Container()
         new_container.name = container_name
+        self.containers.append(new_container)
         return new_container
 
     def delete_container(self, container_name):
@@ -160,24 +161,30 @@ class MockAzureClient:
     def create_blob_from_text(self, container_name, blob_name, text):
         blob = self.get_blob(container_name, blob_name)
         blob.content = text
+        return blob
 
     def get_blob(self, container_name, blob_name):
-        for blob in self.blocks:
+        for blob in self.blocks.get(container_name):
             if blob.name == blob_name:
                 return blob
         return None
 
     def list_blobs(self, container_name):
-        return self.blocks
+        return self.blocks.get(container_name)
 
     def get_blob_content(self, container_name, blob_name):
         blob = self.get_blob(container_name, blob_name)
-        return blob
+        if blob.content:
+            output = StringIO()
+            output.write(blob.content)
+            return output
+
+        return None
 
     def delete_blob(self, container_name, blob_name):
-        for blob in self.blocks:
+        for blob in self.blocks.get(container_name):
             if blob.name == blob_name:
-                self.blocks.remove(blob)
+                self.blocks.get(container_name).remove(blob)
 
     def create_blob_from_file(self, container_name, blob_name, file_path):
         blob = self.get_blob(container_name, blob_name)
@@ -188,7 +195,7 @@ class MockAzureClient:
 
     def create_empty_disk(self, disk_name, size, region=None, snapshot_id=None):
         volume = Disk(location='eastus', creation_data=None)
-        volume.id = '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96/resourceGroups/cloudbridge-azure/providers/Microsoft.Compute/disks/SampleVolume'
+        volume.id = '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96/resourceGroups/cloudbridge-azure/providers/Microsoft.Compute/disks/{0}'.format(disk_name)
         volume.name = disk_name
         volume.disk_size_gb = size
         volume.creation_data = CreationData(create_option=DiskCreateOption.empty)
@@ -205,3 +212,15 @@ class MockAzureClient:
 
     def list_disks(self):
         return self.volumes
+
+    def delete_disk(self, disk_name):
+        disk = self.get_disk(disk_name)
+        self.volumes.remove(disk)
+
+        return True
+
+    def attach_disk(self, vm_name, disk_name, disk_id):
+        return None
+
+    def detach_disk(self, disk_id):
+        return None

+ 64 - 36
cloudbridge/cloud/providers/azure/resources.py

@@ -5,12 +5,15 @@ import inspect
 import json
 from datetime import datetime
 
+from cloudbridge.cloud.providers.azure import helpers as azure_helpers
+
 from azure.common import AzureMissingResourceHttpError
 from msrestazure.azure_exceptions import CloudError
 
 from cloudbridge.cloud.base.resources import BaseBucket, BaseSecurityGroup, BaseSecurityGroupRule, BaseBucketObject, \
     ClientPagedResultList, BaseVolume, BaseAttachmentInfo, BaseInstance, BaseSnapshot
 from cloudbridge.cloud.interfaces import VolumeState, SnapshotState, InstanceState
+from cloudbridge.cloud.interfaces.resources import Instance
 
 NETWORK_RESOURCE_ID = '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{virtualNetworkName}'
 IMAGE_RESOURCE_ID =  '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/images/{imageName}'
@@ -219,16 +222,17 @@ class AzureBucketObject(BaseBucketObject):
         """
         Get the date and time this object was last modified.
         """
-
-        return str(self._key.properties.last_modified)
+        return self._key.properties.last_modified.strftime("%Y-%m-%dT%H:%M:%S.%f")
 
     def iter_content(self):
         """
         Returns this object's content as an
         iterable.
         """
-        blob = self._provider.azure_client.get_blob_content(self._container.name, self._key.name)
-        return blob.content
+        content_stream = self._provider.azure_client.get_blob_content(self._container.name, self._key.name)
+        if content_stream:
+            content_stream.seek(0)
+        return content_stream
 
     def upload(self, data):
         """
@@ -289,7 +293,7 @@ class AzureBucket(BaseBucket):
         except AzureMissingResourceHttpError:
             return None
 
-    def list(self, limit=None, marker=None):
+    def list(self, limit=None, marker=None, prefix=None):
         """
         List all objects within this bucket.
 
@@ -297,7 +301,7 @@ class AzureBucket(BaseBucket):
         :return: List of all available BucketObjects within this bucket.
         """
         objects = [AzureBucketObject(self._provider, self, obj)
-                  for obj in self._provider.azure_client.list_blobs(self.name) ]
+                  for obj in self._provider.azure_client.list_blobs(self.name) if not prefix or prefix and obj.name.startswith(prefix) ]
         return ClientPagedResultList(self._provider, objects,
                                      limit=limit, marker=marker)
 
@@ -321,19 +325,25 @@ class AzureBucket(BaseBucket):
 class AzureVolume(BaseVolume):
 
     VOLUME_STATE_MAP = {
-        'creating': VolumeState.CREATING,
-        'available': VolumeState.AVAILABLE,
-        'in-use': VolumeState.IN_USE,
-        'deleting': VolumeState.CONFIGURING,
-        'deleted': VolumeState.DELETED,
-        'error': VolumeState.ERROR
+        'InProgress': VolumeState.CREATING,
+        'Unattached': VolumeState.AVAILABLE,
+        'Attached': VolumeState.IN_USE,
+        'Deleting': VolumeState.CONFIGURING,
+        'Deleted': VolumeState.DELETED,
+        'Failed': VolumeState.ERROR
     }
 
     def __init__(self, provider, volume):
         super(AzureVolume, self).__init__(provider)
         self._volume = volume
-        self._url_params= TemplateUrlParser.parse(VOLUME_RESOURCE_ID,volume.id)
         self._description = None
+        self._status = 'unknown'
+        if not self._volume.provisioning_state == 'Succeeded':
+            self._status = self._volume.provisioning_state
+        elif self._volume.owner_id:
+            self._status = 'Attached'
+        else:
+            self._status = 'Unattached'
 
     @property
     def id(self):
@@ -370,7 +380,7 @@ class AzureVolume(BaseVolume):
 
     @property
     def create_time(self):
-        return self._volume.time_created
+        return self._volume.time_created.strftime("%Y-%m-%dT%H:%M:%S.%f")
 
     @property
     def zone_id(self):
@@ -378,43 +388,61 @@ class AzureVolume(BaseVolume):
 
     @property
     def source(self):
+        if self._volume.creation_data.source_uri:
+            return self._provider.block_store.snapshots.get(self._volume.creation_data.source_uri)
         return None
 
     @property
     def attachments(self):
-        return None
+        if self._volume.owner_id:
+            return BaseAttachmentInfo(self,
+                                      self._volume.owner_id,
+                                      None)
+        else:
+            return None
 
     def attach(self, instance, device=None):
-        pass
+        """
+        Attach this volume to an instance.
+        """
+        instance_id = instance.id if isinstance(
+            instance,
+            Instance) else instance
+        params = azure_helpers.parse_url(INSTANCE_RESOURCE_ID, instance_id)
+        self._provider.azure_client.attach_disk( params.get(VM_NAME),
+                                                self.id, self.name)
 
     def detach(self, force=False):
-        pass
+        """
+        Detach this volume from an instance.
+        """
+        self._provider.azure_client.detach_disk(self.id)
 
     def create_snapshot(self, name, description=None):
-        pass
+        """
+        Create a snapshot of this Volume.
+        """
+        return self._provider.block_store.snapshots.create(name, self.name)
 
     def delete(self):
-        pass
+        """
+        Delete this volume.
+        """
+        self._provider.azure_client.delete_disk(self.name)
 
     @property
     def state(self):
         return AzureVolume.VOLUME_STATE_MAP.get(
-            self._volume.provisioning_state, VolumeState.UNKNOWN)
+            self._status, VolumeState.UNKNOWN)
 
     def refresh(self):
-        pass
-
-
-class TemplateUrlParser:
-    @staticmethod
-    def parse(template_url, original_url):
-        template_url_parts = template_url.split('/')
-        original_url_parts = original_url.split('/')
-        if len(template_url_parts) != len(original_url_parts):
-            raise Exception('Invalid url parameter passed')
-        d = {}
-        for k, v in zip(template_url_parts, original_url_parts):
-            if k.startswith('{') and k.endswith('}'):
-                d.update({k[1:-1]: v})
-
-        return d
+        """
+        Refreshes the state of this volume by re-querying the cloud provider
+        for its latest state.
+        """
+        try:
+            self._volume = self._provider.azure_client.get_disk(self.name)
+        except (CloudError, ValueError):
+            # The volume no longer exists and cannot be refreshed.
+            # set the status to unknown
+            self._status = 'unknown'

+ 40 - 23
cloudbridge/cloud/providers/azure/services.py

@@ -4,16 +4,18 @@ from azure.common import AzureMissingResourceHttpError
 from msrestazure.azure_exceptions import CloudError
 
 from cloudbridge.cloud.interfaces.resources import PlacementZone, Snapshot
-from cloudbridge.cloud.providers.azure.azure_client import FilterList
+
 from .resources import SUBNET_RESOURCE_ID, NETWORK_NAME, SUBNET_NAME, NETWORK_RESOURCE_ID, \
     INSTANCE_RESOURCE_ID, VM_NAME, IMAGE_RESOURCE_ID, RESOURCE_GROUP_NAME, IMAGE_NAME, SNAPSHOT_RESOURCE_ID, \
     SNAPSHOT_NAME, VOLUME_RESOURCE_ID, VOLUME_NAME, NETWORK_SECURITY_GROUP_RESOURCE_ID, SECURITY_GROUP_NAME, \
-    TemplateUrlParser, AzureVolume
+    AzureVolume
 
 from cloudbridge.cloud.base.resources import ClientPagedResultList
 from cloudbridge.cloud.base.services import BaseObjectStoreService, BaseSecurityGroupService, BaseSecurityService, \
     BaseVolumeService, BaseBlockStoreService
 
+from cloudbridge.cloud.providers.azure import helpers as azure_helpers
+
 from .resources import AzureBucket, AzureSecurityGroup
 
 log = logging.getLogger(__name__)
@@ -35,7 +37,7 @@ class AzureSecurityService(BaseSecurityService):
         :rtype: ``object`` of :class:`.KeyPairService`
         :return: a KeyPairService object
         """
-        pass
+        raise NotImplementedError('AzureSecurityService not implemented this property')
 
     @property
     def security_groups(self):
@@ -54,13 +56,15 @@ class AzureSecurityGroupService(BaseSecurityGroupService):
 
     def get(self, sg_id):
         try:
-            params = TemplateUrlParser.parse(NETWORK_SECURITY_GROUP_RESOURCE_ID, sg_id)
+            params = azure_helpers.parse_url(NETWORK_SECURITY_GROUP_RESOURCE_ID, sg_id)
             sgs = self.provider.azure_client.get_security_group(params.get(SECURITY_GROUP_NAME))
             return AzureSecurityGroup(self.provider, sgs) if sgs else None
 
-        except CloudError:
+        except CloudError as cloudError:
+            log.exception(cloudError.message)
             return None
 
+
     def list(self, limit=None, marker=None):
         sgs = [AzureSecurityGroup(self.provider, sg)
                for sg in self.provider.azure_client.list_security_group()]
@@ -69,25 +73,21 @@ class AzureSecurityGroupService(BaseSecurityGroupService):
     def create(self, name, description, network_id):
         parameters = {"location": self.provider.region_name}
         sg = self.provider.azure_client.create_security_group(name, parameters)
-        if sg:
-            return AzureSecurityGroup(self.provider, sg)
-        return None
+        return AzureSecurityGroup(self.provider, sg)
 
     def find(self, name, limit=None, marker=None):
         """
         Searches for a security group by a given list of attributes.
         """
-        filter = {'name': name}
-        filtered_security_groups = FilterList(self.provider.azure_client.list_security_group())
-        filtered_security_groups.filter(filter)
-        security_groups = [AzureSecurityGroup(self.provider, security_group)
-                           for security_group in filtered_security_groups]
+        filters = {'name': name}
+        sgs = [AzureSecurityGroup(self.provider, security_group)
+                           for security_group in azure_helpers.filter(self.provider.azure_client.list_security_group(), filters)]
 
-        return ClientPagedResultList(self.provider, security_groups,
+        return ClientPagedResultList(self.provider, sgs,
                                      limit=limit, marker=marker)
 
     def delete(self, group_id):
-        params = TemplateUrlParser.parse(NETWORK_SECURITY_GROUP_RESOURCE_ID, group_id)
+        params = azure_helpers.parse_url(NETWORK_SECURITY_GROUP_RESOURCE_ID, group_id)
         return self.provider.azure_client.delete_security_group(params.get(SECURITY_GROUP_NAME))
 
 
@@ -106,15 +106,17 @@ class AzureObjectStoreService(BaseObjectStoreService):
                 return AzureBucket(self.provider, bucket)
             else:
                 return None
-        except AzureMissingResourceHttpError:
+        except AzureMissingResourceHttpError as error:
+            log.exception(error.message)
             return None
 
     def find(self, name, limit=None, marker=None):
         """
         Searches for a bucket by a given list of attributes.
         """
+        filters = {'name': name}
         buckets = [AzureBucket(self.provider, bucket)
-                   for bucket in self.provider.azure_client.list_containers({'name': name})]
+                   for bucket in azure_helpers.filter(self.provider.azure_client.list_containers(), filters)]
         return ClientPagedResultList(self.provider, buckets,
                                      limit=limit, marker=marker)
 
@@ -148,7 +150,7 @@ class AzureBlockStoreService(BaseBlockStoreService):
 
     @property
     def snapshots(self):
-        pass
+        raise NotImplementedError('AzureBlockStoreService not implemented.')
 
 
 class AzureVolumeService(BaseVolumeService):
@@ -156,11 +158,26 @@ class AzureVolumeService(BaseVolumeService):
         super(AzureVolumeService, self).__init__(provider)
 
     def get(self, volume_id):
-        volume = self.provider.azure_client.get_disk(volume_id)
-        return AzureVolume(self.provider, volume)
+        try:
+            params = azure_helpers.parse_url(VOLUME_RESOURCE_ID, volume_id)
+            volume = self.provider.azure_client.get_disk(params.get(VOLUME_NAME))
+            if volume:
+                return AzureVolume(self.provider, volume)
+
+            return None
+        except CloudError as cloudError:
+            log.exception(cloudError.message)
+            return None
 
     def find(self, name, limit=None, marker=None):
-        raise NotImplementedError('AzureVolumeService not imeplemented this method')
+        """
+        Searches for a volume by a given list of attributes.
+        """
+        filters = {'name': name}
+        cb_vols = [AzureVolume(self.provider, volume)
+                   for volume in azure_helpers.filter(self.provider.azure_client.list_disks(), filters)]
+        return ClientPagedResultList(self.provider, cb_vols,
+                                     limit=limit, marker=marker)
 
     def list(self, limit=None, marker=None):
         azure_vols = self.provider.azure_client.list_disks()
@@ -171,8 +188,8 @@ class AzureVolumeService(BaseVolumeService):
     def create(self, name, size, zone=None, snapshot=None, description=None):
         zone_id = zone.id if isinstance(zone, PlacementZone) else zone
         snapshot_id = snapshot.id if isinstance(snapshot, Snapshot) and snapshot else snapshot
-        azure_vol = self.provider.azure_client.create_empty_disk(name, size, zone_id, snapshot_id)
-
+        self.provider.azure_client.create_empty_disk(name, size, zone_id, snapshot_id)
+        azure_vol = self.provider.azure_client.get_disk(name)
         cb_vol = AzureVolume(self.provider, azure_vol)
         if description:
             cb_vol.description = description

+ 6 - 6
test/test_azure_object_store_service.py

@@ -25,14 +25,14 @@ class AzureObjectStoreServiceTestCase(ProviderTestBase):
         containerList = self.provider.object_store.list()
         print("List Container - " + str(containerList))
         self.assertEqual(
-            len(containerList), 1)
+            len(containerList), 2)
 
     @helpers.skipIfNoService(['object_store'])
     def test_azure_bucket_find_Exist(self):
         container = self.provider.object_store.find("container")
         print("Find Exist - " + str(container))
         self.assertEqual(
-            len(container) ,1)
+            len(container) ,2)
 
     @helpers.skipIfNoService(['object_store'])
     def test_azure_bucket_find_NotExist(self):
@@ -52,7 +52,7 @@ class AzureObjectStoreServiceTestCase(ProviderTestBase):
 
     @helpers.skipIfNoService(['object_store'])
     def test_azure_bucket_get_NotExist(self):
-        container = self.provider.object_store.get("container3")
+        container = self.provider.object_store.get("container23")
         print("Get Not Exist - " + str(container))
         self.assertEqual(
             str(container) , 'None')
@@ -123,7 +123,7 @@ class AzureObjectStoreServiceTestCase(ProviderTestBase):
         content = block.iter_content()
         print("Iter content  - " + str(content))
         self.assertEqual(
-            str(content),'blob2Content' )
+            content.getvalue(), 'blob2Content' )
 
     @helpers.skipIfNoService(['object_store'])
     def test_azure_bucket_object_iter_content_ifBlobNotExists(self):
@@ -142,7 +142,7 @@ class AzureObjectStoreServiceTestCase(ProviderTestBase):
         block = blocks[0]
         block.upload('blob1Content')
         self.assertEqual(
-            block.iter_content(), 'blob1Content')
+            block.iter_content().getvalue(), 'blob1Content')
 
     @helpers.skipIfNoService(['object_store'])
     def test_azure_bucket_object_delete(self):
@@ -163,7 +163,7 @@ class AzureObjectStoreServiceTestCase(ProviderTestBase):
         block = blocks[0]
         block.upload_from_file('blob2Content')
         self.assertEqual(
-            block.iter_content(), 'blob2Content')
+            block.iter_content().getvalue(), 'blob2Content')
 
 
     @helpers.skipIfNoService(['object_store'])

+ 3 - 1
test/test_azure_security_service.py

@@ -12,7 +12,9 @@ class AzureSecurityServiceTestCase(ProviderTestBase):
     def __init__(self, methodName, provider):
         super(AzureSecurityServiceTestCase, self).__init__(
             methodName=methodName, provider=provider)
-        self.key_pairs = self.provider.security.key_pairs
+        with self.assertRaises(NotImplementedError):
+            self.key_pairs = self.provider.security.key_pairs
+
         self.security_groups = self.provider.security.security_groups
 
     @helpers.skipIfNoService(['security.security_groups'])

+ 55 - 8
test/test_azure_volume_service.py

@@ -12,31 +12,78 @@ class AzureVolumeServiceTestCase(ProviderTestBase):
     def __init__(self, methodName, provider):
         super(AzureVolumeServiceTestCase, self).__init__(
             methodName=methodName, provider=provider)
-        self.snapshots = self.provider.block_store.snapshots
 
     @helpers.skipIfNoService(['block_store.volumes'])
-    def test_azure_volume_create(self):
+    def test_azure_volume_create_and_get(self):
         volume = self.provider.block_store.volumes.create("MyVolume",1, description='My volume')
         print("Create Volume - " + str(volume))
         self.assertTrue(
             volume.name == "MyVolume" , "Volume name should be MyVolume")
 
+        volume = self.provider.block_store.volumes.get(
+            "/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96/resourceGroups/cloudbridge-azure/providers/Microsoft.Compute/disks/MyVolume")
+        print("Get Volume  - " + str(volume))
+        self.assertTrue(
+            volume.name == "MyVolume", "Volume name should be MyVolume")
+
+        volume.delete()
 
     @helpers.skipIfNoService(['block_store.volumes'])
-    def test_azure_volume_get(self):
-        volume = self.provider.block_store.volumes.get("MyVolume")
-        print("Get Volume  - " + str(volume))
+    def test_azure_volume_delete(self):
+        volume = self.provider.block_store.volumes.create("MyVolume", 1, description='My volume')
+        volume.refresh()
+        print("Create Volume - " + str(volume))
         self.assertTrue(
             volume.name == "MyVolume", "Volume name should be MyVolume")
+        volume.delete()
+        volume1 = self.provider.block_store.volumes.get("/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96/resourceGroups/cloudbridge-azure/providers/Microsoft.Compute/disks/MyVolume")
+        self.assertTrue(
+            volume1 is None, "Volume still exists")
 
     @helpers.skipIfNoService(['block_store.volumes'])
-    def test_azure_volume_find(self):
+    def test_azure_volume_attach(self):
+        volume = self.provider.block_store.volumes.create("MyVolume", 1, description='My volume')
+        self.assertTrue(
+            volume.name == "MyVolume", "Volume name should be MyVolume")
+        volume.attach('/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96/resourceGroups/CloudBridge-Azure/providers/Microsoft.Compute/virtualMachines/ubuntu-intro1')
+        volume.delete()
+
+    @helpers.skipIfNoService(['block_store.volumes'])
+    def test_azure_volume_dettach(self):
+        volume = self.provider.block_store.volumes.create("MyVolume", 1, description='My volume')
+        self.assertTrue(
+            volume.name == "MyVolume", "Volume name should be MyVolume")
+        volume.detach()
+        volume.delete()
+
+    @helpers.skipIfNoService(['block_store.volumes'])
+    def test_azure_volume_create_snapshot(self):
+        volume = self.provider.block_store.volumes.create("MyVolume", 1, description='My volume')
+        self.assertTrue(
+            volume.name == "MyVolume", "Volume name should be MyVolume")
         with self.assertRaises(NotImplementedError):
-            volumes = self.provider.block_store.volumes.find("MyVolume")
+            volume.create_snapshot('MySnap')
+
+        volume.delete()
+
+
+    @helpers.skipIfNoService(['block_store.volumes'])
+    def test_azure_volume_get_ifNotExist(self):
+        volume = self.provider.block_store.volumes.get("/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96/resourceGroups/cloudbridge-azure/providers/Microsoft.Compute/disks/MyVolume123")
+        self.assertTrue(
+            volume is None, "Volume should not be available")
+
+    @helpers.skipIfNoService(['block_store.volumes'])
+    def test_azure_volume_find(self):
+        volumes = self.provider.block_store.volumes.find("Volume")
+        self.assertTrue(
+            len(volumes) == 2, "Volume should not be available")
+
+
 
     @helpers.skipIfNoService(['block_store.volumes'])
     def test_azure_volume_list(self):
         volume_list = self.provider.block_store.volumes.list()
         print("Volume List - " + str(volume_list))
         self.assertEqual(
-            len(volume_list), 3)
+            len(volume_list), 2)