Răsfoiți Sursa

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 ani în urmă
părinte
comite
a8923b0c98

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

@@ -1,4 +1,5 @@
 import logging
 import logging
+from io import BytesIO
 
 
 from azure.common.credentials import ServicePrincipalCredentials
 from azure.common.credentials import ServicePrincipalCredentials
 from azure.mgmt.compute import ComputeManagementClient
 from azure.mgmt.compute import ComputeManagementClient
@@ -77,11 +78,7 @@ class AzureClient(object):
     def list_locations(self):
     def list_locations(self):
         return self.subscription_client.subscriptions.list_locations(self.subscription_id)
         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)
         return self.network_management_client.network_security_groups.list(self.resource_group_name)
 
 
     def create_security_group(self, name, parameters):
     def create_security_group(self, name, parameters):
@@ -107,10 +104,8 @@ class AzureClient(object):
     def delete_security_group(self, name):
     def delete_security_group(self, name):
         return self.network_management_client.network_security_groups.delete(self.resource_group_name, 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):
     def create_container(self, container_name):
         self.blob_service.create_container(container_name, public_access=PublicAccess.Container)
         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)
         return self.blob_service.make_blob_url(container_name, blob_name)
 
 
     def get_blob_content(self, 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):
     def create_empty_disk(self, disk_name, size, region=None, snapshot_id=None):
         if snapshot_id:
         if snapshot_id:
@@ -159,10 +156,10 @@ class AzureClient(object):
                 'creation_data': {
                 'creation_data': {
                     'create_option': 'empty'
                     '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):
     def create_snapshot_disk(self, disk_name, snapshot_id, region=None):
         async_creation = self.compute_client.disks.create_or_update(
         async_creation = self.compute_client.disks.create_or_update(
@@ -185,18 +182,47 @@ class AzureClient(object):
     def list_disks(self):
     def list_disks(self):
         return self.compute_client.disks.list()
         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.compute.models import Disk, CreationData, DiskCreateOption
 from azure.mgmt.network.models import NetworkSecurityGroup
 from azure.mgmt.network.models import NetworkSecurityGroup
 from azure.mgmt.network.models import SecurityRule
 from azure.mgmt.network.models import SecurityRule
 from azure.mgmt.resource.resources.models import ResourceGroup
 from azure.mgmt.resource.resources.models import ResourceGroup
 from azure.storage.blob.models import Container, Blob
 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:
 class MockAzureClient:
@@ -57,13 +59,14 @@ class MockAzureClient:
 
 
     block2 = Blob()
     block2 = Blob()
     block2.name = "block2"
     block2.name = "block2"
-    block2.content = "blob2Content"
+    block2.content ="blob2Content"
 
 
     block3 = Blob()
     block3 = Blob()
     block3.name = "block3"
     block3.name = "block3"
     block3.content = None
     block3.content = None
 
 
-    blocks = [block1, block2, block3]
+    blocks = {'container1':[block1, block2, block3],
+              'container2':[block1, block2, block3]}
 
 
     rg = ResourceGroup(location='westus')
     rg = ResourceGroup(location='westus')
     rg.name = "testResourceGroup"
     rg.name = "testResourceGroup"
@@ -98,8 +101,7 @@ class MockAzureClient:
         self.security_groups.append(sg_create)
         self.security_groups.append(sg_create)
         return sg_create
         return sg_create
 
 
-    def list_security_group(self, filters=None):
-
+    def list_security_group(self):
         return self.security_groups
         return self.security_groups
 
 
     def delete_security_group(self, name):
     def delete_security_group(self, name):
@@ -143,14 +145,13 @@ class MockAzureClient:
                 return container
                 return container
         return None
         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):
     def create_container(self, container_name):
         new_container = Container()
         new_container = Container()
         new_container.name = container_name
         new_container.name = container_name
+        self.containers.append(new_container)
         return new_container
         return new_container
 
 
     def delete_container(self, container_name):
     def delete_container(self, container_name):
@@ -160,24 +161,30 @@ class MockAzureClient:
     def create_blob_from_text(self, container_name, blob_name, text):
     def create_blob_from_text(self, container_name, blob_name, text):
         blob = self.get_blob(container_name, blob_name)
         blob = self.get_blob(container_name, blob_name)
         blob.content = text
         blob.content = text
+        return blob
 
 
     def get_blob(self, container_name, blob_name):
     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:
             if blob.name == blob_name:
                 return blob
                 return blob
         return None
         return None
 
 
     def list_blobs(self, container_name):
     def list_blobs(self, container_name):
-        return self.blocks
+        return self.blocks.get(container_name)
 
 
     def get_blob_content(self, container_name, blob_name):
     def get_blob_content(self, container_name, blob_name):
         blob = self.get_blob(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):
     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:
             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):
     def create_blob_from_file(self, container_name, blob_name, file_path):
         blob = self.get_blob(container_name, blob_name)
         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):
     def create_empty_disk(self, disk_name, size, region=None, snapshot_id=None):
         volume = Disk(location='eastus', creation_data=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.name = disk_name
         volume.disk_size_gb = size
         volume.disk_size_gb = size
         volume.creation_data = CreationData(create_option=DiskCreateOption.empty)
         volume.creation_data = CreationData(create_option=DiskCreateOption.empty)
@@ -205,3 +212,15 @@ class MockAzureClient:
 
 
     def list_disks(self):
     def list_disks(self):
         return self.volumes
         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
 import json
 from datetime import datetime
 from datetime import datetime
 
 
+from cloudbridge.cloud.providers.azure import helpers as azure_helpers
+
 from azure.common import AzureMissingResourceHttpError
 from azure.common import AzureMissingResourceHttpError
 from msrestazure.azure_exceptions import CloudError
 from msrestazure.azure_exceptions import CloudError
 
 
 from cloudbridge.cloud.base.resources import BaseBucket, BaseSecurityGroup, BaseSecurityGroupRule, BaseBucketObject, \
 from cloudbridge.cloud.base.resources import BaseBucket, BaseSecurityGroup, BaseSecurityGroupRule, BaseBucketObject, \
     ClientPagedResultList, BaseVolume, BaseAttachmentInfo, BaseInstance, BaseSnapshot
     ClientPagedResultList, BaseVolume, BaseAttachmentInfo, BaseInstance, BaseSnapshot
 from cloudbridge.cloud.interfaces import VolumeState, SnapshotState, InstanceState
 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}'
 NETWORK_RESOURCE_ID = '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{virtualNetworkName}'
 IMAGE_RESOURCE_ID =  '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/images/{imageName}'
 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.
         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):
     def iter_content(self):
         """
         """
         Returns this object's content as an
         Returns this object's content as an
         iterable.
         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):
     def upload(self, data):
         """
         """
@@ -289,7 +293,7 @@ class AzureBucket(BaseBucket):
         except AzureMissingResourceHttpError:
         except AzureMissingResourceHttpError:
             return None
             return None
 
 
-    def list(self, limit=None, marker=None):
+    def list(self, limit=None, marker=None, prefix=None):
         """
         """
         List all objects within this bucket.
         List all objects within this bucket.
 
 
@@ -297,7 +301,7 @@ class AzureBucket(BaseBucket):
         :return: List of all available BucketObjects within this bucket.
         :return: List of all available BucketObjects within this bucket.
         """
         """
         objects = [AzureBucketObject(self._provider, self, obj)
         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,
         return ClientPagedResultList(self._provider, objects,
                                      limit=limit, marker=marker)
                                      limit=limit, marker=marker)
 
 
@@ -321,19 +325,25 @@ class AzureBucket(BaseBucket):
 class AzureVolume(BaseVolume):
 class AzureVolume(BaseVolume):
 
 
     VOLUME_STATE_MAP = {
     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):
     def __init__(self, provider, volume):
         super(AzureVolume, self).__init__(provider)
         super(AzureVolume, self).__init__(provider)
         self._volume = volume
         self._volume = volume
-        self._url_params= TemplateUrlParser.parse(VOLUME_RESOURCE_ID,volume.id)
         self._description = None
         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
     @property
     def id(self):
     def id(self):
@@ -370,7 +380,7 @@ class AzureVolume(BaseVolume):
 
 
     @property
     @property
     def create_time(self):
     def create_time(self):
-        return self._volume.time_created
+        return self._volume.time_created.strftime("%Y-%m-%dT%H:%M:%S.%f")
 
 
     @property
     @property
     def zone_id(self):
     def zone_id(self):
@@ -378,43 +388,61 @@ class AzureVolume(BaseVolume):
 
 
     @property
     @property
     def source(self):
     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
         return None
 
 
     @property
     @property
     def attachments(self):
     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):
     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):
     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):
     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):
     def delete(self):
-        pass
+        """
+        Delete this volume.
+        """
+        self._provider.azure_client.delete_disk(self.name)
 
 
     @property
     @property
     def state(self):
     def state(self):
         return AzureVolume.VOLUME_STATE_MAP.get(
         return AzureVolume.VOLUME_STATE_MAP.get(
-            self._volume.provisioning_state, VolumeState.UNKNOWN)
+            self._status, VolumeState.UNKNOWN)
 
 
     def refresh(self):
     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 msrestazure.azure_exceptions import CloudError
 
 
 from cloudbridge.cloud.interfaces.resources import PlacementZone, Snapshot
 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, \
 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, \
     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, \
     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.resources import ClientPagedResultList
 from cloudbridge.cloud.base.services import BaseObjectStoreService, BaseSecurityGroupService, BaseSecurityService, \
 from cloudbridge.cloud.base.services import BaseObjectStoreService, BaseSecurityGroupService, BaseSecurityService, \
     BaseVolumeService, BaseBlockStoreService
     BaseVolumeService, BaseBlockStoreService
 
 
+from cloudbridge.cloud.providers.azure import helpers as azure_helpers
+
 from .resources import AzureBucket, AzureSecurityGroup
 from .resources import AzureBucket, AzureSecurityGroup
 
 
 log = logging.getLogger(__name__)
 log = logging.getLogger(__name__)
@@ -35,7 +37,7 @@ class AzureSecurityService(BaseSecurityService):
         :rtype: ``object`` of :class:`.KeyPairService`
         :rtype: ``object`` of :class:`.KeyPairService`
         :return: a KeyPairService object
         :return: a KeyPairService object
         """
         """
-        pass
+        raise NotImplementedError('AzureSecurityService not implemented this property')
 
 
     @property
     @property
     def security_groups(self):
     def security_groups(self):
@@ -54,13 +56,15 @@ class AzureSecurityGroupService(BaseSecurityGroupService):
 
 
     def get(self, sg_id):
     def get(self, sg_id):
         try:
         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))
             sgs = self.provider.azure_client.get_security_group(params.get(SECURITY_GROUP_NAME))
             return AzureSecurityGroup(self.provider, sgs) if sgs else None
             return AzureSecurityGroup(self.provider, sgs) if sgs else None
 
 
-        except CloudError:
+        except CloudError as cloudError:
+            log.exception(cloudError.message)
             return None
             return None
 
 
+
     def list(self, limit=None, marker=None):
     def list(self, limit=None, marker=None):
         sgs = [AzureSecurityGroup(self.provider, sg)
         sgs = [AzureSecurityGroup(self.provider, sg)
                for sg in self.provider.azure_client.list_security_group()]
                for sg in self.provider.azure_client.list_security_group()]
@@ -69,25 +73,21 @@ class AzureSecurityGroupService(BaseSecurityGroupService):
     def create(self, name, description, network_id):
     def create(self, name, description, network_id):
         parameters = {"location": self.provider.region_name}
         parameters = {"location": self.provider.region_name}
         sg = self.provider.azure_client.create_security_group(name, parameters)
         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):
     def find(self, name, limit=None, marker=None):
         """
         """
         Searches for a security group by a given list of attributes.
         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)
                                      limit=limit, marker=marker)
 
 
     def delete(self, group_id):
     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))
         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)
                 return AzureBucket(self.provider, bucket)
             else:
             else:
                 return None
                 return None
-        except AzureMissingResourceHttpError:
+        except AzureMissingResourceHttpError as error:
+            log.exception(error.message)
             return None
             return None
 
 
     def find(self, name, limit=None, marker=None):
     def find(self, name, limit=None, marker=None):
         """
         """
         Searches for a bucket by a given list of attributes.
         Searches for a bucket by a given list of attributes.
         """
         """
+        filters = {'name': name}
         buckets = [AzureBucket(self.provider, bucket)
         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,
         return ClientPagedResultList(self.provider, buckets,
                                      limit=limit, marker=marker)
                                      limit=limit, marker=marker)
 
 
@@ -148,7 +150,7 @@ class AzureBlockStoreService(BaseBlockStoreService):
 
 
     @property
     @property
     def snapshots(self):
     def snapshots(self):
-        pass
+        raise NotImplementedError('AzureBlockStoreService not implemented.')
 
 
 
 
 class AzureVolumeService(BaseVolumeService):
 class AzureVolumeService(BaseVolumeService):
@@ -156,11 +158,26 @@ class AzureVolumeService(BaseVolumeService):
         super(AzureVolumeService, self).__init__(provider)
         super(AzureVolumeService, self).__init__(provider)
 
 
     def get(self, volume_id):
     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):
     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):
     def list(self, limit=None, marker=None):
         azure_vols = self.provider.azure_client.list_disks()
         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):
     def create(self, name, size, zone=None, snapshot=None, description=None):
         zone_id = zone.id if isinstance(zone, PlacementZone) else zone
         zone_id = zone.id if isinstance(zone, PlacementZone) else zone
         snapshot_id = snapshot.id if isinstance(snapshot, Snapshot) and snapshot else snapshot
         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)
         cb_vol = AzureVolume(self.provider, azure_vol)
         if description:
         if description:
             cb_vol.description = 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()
         containerList = self.provider.object_store.list()
         print("List Container - " + str(containerList))
         print("List Container - " + str(containerList))
         self.assertEqual(
         self.assertEqual(
-            len(containerList), 1)
+            len(containerList), 2)
 
 
     @helpers.skipIfNoService(['object_store'])
     @helpers.skipIfNoService(['object_store'])
     def test_azure_bucket_find_Exist(self):
     def test_azure_bucket_find_Exist(self):
         container = self.provider.object_store.find("container")
         container = self.provider.object_store.find("container")
         print("Find Exist - " + str(container))
         print("Find Exist - " + str(container))
         self.assertEqual(
         self.assertEqual(
-            len(container) ,1)
+            len(container) ,2)
 
 
     @helpers.skipIfNoService(['object_store'])
     @helpers.skipIfNoService(['object_store'])
     def test_azure_bucket_find_NotExist(self):
     def test_azure_bucket_find_NotExist(self):
@@ -52,7 +52,7 @@ class AzureObjectStoreServiceTestCase(ProviderTestBase):
 
 
     @helpers.skipIfNoService(['object_store'])
     @helpers.skipIfNoService(['object_store'])
     def test_azure_bucket_get_NotExist(self):
     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))
         print("Get Not Exist - " + str(container))
         self.assertEqual(
         self.assertEqual(
             str(container) , 'None')
             str(container) , 'None')
@@ -123,7 +123,7 @@ class AzureObjectStoreServiceTestCase(ProviderTestBase):
         content = block.iter_content()
         content = block.iter_content()
         print("Iter content  - " + str(content))
         print("Iter content  - " + str(content))
         self.assertEqual(
         self.assertEqual(
-            str(content),'blob2Content' )
+            content.getvalue(), 'blob2Content' )
 
 
     @helpers.skipIfNoService(['object_store'])
     @helpers.skipIfNoService(['object_store'])
     def test_azure_bucket_object_iter_content_ifBlobNotExists(self):
     def test_azure_bucket_object_iter_content_ifBlobNotExists(self):
@@ -142,7 +142,7 @@ class AzureObjectStoreServiceTestCase(ProviderTestBase):
         block = blocks[0]
         block = blocks[0]
         block.upload('blob1Content')
         block.upload('blob1Content')
         self.assertEqual(
         self.assertEqual(
-            block.iter_content(), 'blob1Content')
+            block.iter_content().getvalue(), 'blob1Content')
 
 
     @helpers.skipIfNoService(['object_store'])
     @helpers.skipIfNoService(['object_store'])
     def test_azure_bucket_object_delete(self):
     def test_azure_bucket_object_delete(self):
@@ -163,7 +163,7 @@ class AzureObjectStoreServiceTestCase(ProviderTestBase):
         block = blocks[0]
         block = blocks[0]
         block.upload_from_file('blob2Content')
         block.upload_from_file('blob2Content')
         self.assertEqual(
         self.assertEqual(
-            block.iter_content(), 'blob2Content')
+            block.iter_content().getvalue(), 'blob2Content')
 
 
 
 
     @helpers.skipIfNoService(['object_store'])
     @helpers.skipIfNoService(['object_store'])

+ 3 - 1
test/test_azure_security_service.py

@@ -12,7 +12,9 @@ class AzureSecurityServiceTestCase(ProviderTestBase):
     def __init__(self, methodName, provider):
     def __init__(self, methodName, provider):
         super(AzureSecurityServiceTestCase, self).__init__(
         super(AzureSecurityServiceTestCase, self).__init__(
             methodName=methodName, provider=provider)
             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
         self.security_groups = self.provider.security.security_groups
 
 
     @helpers.skipIfNoService(['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):
     def __init__(self, methodName, provider):
         super(AzureVolumeServiceTestCase, self).__init__(
         super(AzureVolumeServiceTestCase, self).__init__(
             methodName=methodName, provider=provider)
             methodName=methodName, provider=provider)
-        self.snapshots = self.provider.block_store.snapshots
 
 
     @helpers.skipIfNoService(['block_store.volumes'])
     @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')
         volume = self.provider.block_store.volumes.create("MyVolume",1, description='My volume')
         print("Create Volume - " + str(volume))
         print("Create Volume - " + str(volume))
         self.assertTrue(
         self.assertTrue(
             volume.name == "MyVolume" , "Volume name should be MyVolume")
             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'])
     @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(
         self.assertTrue(
             volume.name == "MyVolume", "Volume name should be MyVolume")
             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'])
     @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):
         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'])
     @helpers.skipIfNoService(['block_store.volumes'])
     def test_azure_volume_list(self):
     def test_azure_volume_list(self):
         volume_list = self.provider.block_store.volumes.list()
         volume_list = self.provider.block_store.volumes.list()
         print("Volume List - " + str(volume_list))
         print("Volume List - " + str(volume_list))
         self.assertEqual(
         self.assertEqual(
-            len(volume_list), 3)
+            len(volume_list), 2)