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

Implemented changes to support name and description change

vikramdoda 9 лет назад
Родитель
Сommit
84f6231ef9

+ 4 - 4
azure_integration_test/test_integration_azure_snapshot_service.py

@@ -7,8 +7,8 @@ class AzureIntegrationSnapshotServiceTestCase(helpers.ProviderTestBase):
 
     @helpers.skipIfNoService(['block_store'])
     def test_azure_snapshot_service(self):
-        snapshot_name = '{0}'.format(uuid.uuid4())
-        volume_name = '{0}'.format(uuid.uuid4())
+        snapshot_name = '{0}'.format(uuid.uuid4().hex[:6])
+        volume_name = '{0}'.format(uuid.uuid4().hex[:6])
 
         snapshot_list_before_create = \
             self.provider.block_store.snapshots.list()
@@ -64,8 +64,8 @@ class AzureIntegrationSnapshotServiceTestCase(helpers.ProviderTestBase):
             self.provider.block_store.snapshots.list()
         print(str(len(snapshot_list_after_delete)))
 
-        self.assertTrue(len(snapshot_list_after_delete),
-                        len(snapshot_list_before_delete) - 1)
+        self.assertEqual(len(snapshot_list_after_delete),
+                         len(snapshot_list_before_delete) - 1)
 
         volume.delete()
         vol.delete()

+ 5 - 9
azure_test/test_azure_snapshots_service.py

@@ -7,12 +7,12 @@ from cloudbridge.cloud.interfaces import SnapshotState
 class AzureSnapshotsServiceTestCase(ProviderTestBase):
     @helpers.skipIfNoService(['block_store.snapshots'])
     def test_azure_snapshot_create_and_get(self):
-        snapshot_id = "/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96'\
+        volume_id = "/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96'\
             '/resourceGroups/cloudbridge-azure'\
-            '/providers/Microsoft.Compute/snapshots/MySnapshot123"
+            '/providers/Microsoft.Compute/disks/MySnapshotDisk123"
         snapshot = self.provider.block_store. \
             snapshots.create("MySnapshot",
-                             snapshot_id)
+                             volume_id)
         snapshot.description = 'My snapshot'
         print("Create Snapshot - " + str(snapshot))
         self.assertTrue(
@@ -24,14 +24,10 @@ class AzureSnapshotsServiceTestCase(ProviderTestBase):
         self.assertIsNotNone(snapshot.volume_id)
         self.assertIsNotNone(snapshot.create_time)
         snapshot.name = 'MySnapNewName'
-        snapshot = self.provider.block_store.snapshots.get(
-                "/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96'\
-                '/resourceGroups/cloudbridge-azure'\
-                '/providers/Microsoft.Compute'\
-                /snapshots/MySnapshot")
+        snapshot = self.provider.block_store.snapshots.get(snapshot.id)
         print("Get Snapshot  - " + str(snapshot))
         self.assertTrue(
-            snapshot.name == "MySnapshot",
+            snapshot.name == "MySnapNewName",
             "Snapshot name should be MySnapshot")
 
         snapshot.delete()

+ 33 - 104
cloudbridge/cloud/providers/azure/azure_client.py

@@ -1,4 +1,5 @@
 import logging
+
 from io import BytesIO
 
 from azure.common.credentials import ServicePrincipalCredentials
@@ -176,62 +177,33 @@ class AzureClient(object):
                                              blob_name, out_stream)
         return out_stream
 
-    def create_empty_disk(self, disk_name, size,
-                          region=None, snapshot_id=None,
-                          description=None):
-
-        if snapshot_id:
-            return self.create_snapshot_disk(disk_name,
-                                             snapshot_id, region=region)
-
-        params = {
-            'location': region or self.region_name,
-            'disk_size_gb': size,
-            'creation_data': {
-                'create_option': 'empty'
-            }
-        }
-        if description:
-            params['tags'] = {'Description': description}
-
-        async_creation = self.compute_client.disks.create_or_update(
+    def create_empty_disk(self, disk_name, params):
+        return self.compute_client.disks.create_or_update(
             self.resource_group_name,
             disk_name,
             params,
             raw=True
         )
-        return async_creation
 
-    def create_snapshot_disk(self, disk_name, snapshot_id, region=None):
-        disk_response = self.compute_client.disks.create_or_update(
+    def create_snapshot_disk(self, disk_name, params):
+        return self.compute_client.disks.create_or_update(
             self.resource_group_name,
             disk_name,
-            {
-                'location': region or self.region_name,
-                'creation_data': {
-                    'create_option': 'copy',
-                    'source_uri': snapshot_id
-                }
-            },
+            params,
             raw=True
         )
 
-        return disk_response
-
     def list_snapshots(self):
         return self.compute_client.snapshots. \
             list_by_resource_group(self.resource_group_name)
 
-    def update_disk_tags(self, disk_name, tags, region=None):
-        disk_result = self.compute_client.disks.update(
+    def update_disk_tags(self, disk_name, tags):
+        return self.compute_client.disks.update(
             self.resource_group_name,
             disk_name,
-            {
-                'tags': tags
-            },
+            {'tags': tags},
             raw=True
         )
-        return disk_result
 
     def get_disk(self, disk_name):
         return self.compute_client.disks. \
@@ -246,89 +218,46 @@ class AzureClient(object):
             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),
-                'name': disk_name,
-                'create_option': 'attach',
-                'managed_disk': {
-                    'id': disk_id
-                }
-            })
-            self.compute_client.virtual_machines.create_or_update(
-                self.resource_group_name,
-                vm.name,
-                vm,
-                raw=True
-            )
-
-    def detach_disk(self, disk_id):
-        virtual_machine = None
-        for index, vm in enumerate(
-                self.compute_client.virtual_machines.list(
-                    self.resource_group_name)):
-            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:
-            self.compute_client.virtual_machines.create_or_update(
-                self.resource_group_name,
-                virtual_machine.name,
-                virtual_machine,
-                raw=True
-            )
-
     def get_snapshot(self, snapshot_name):
         return self.compute_client.snapshots.get(self.resource_group_name,
                                                  snapshot_name)
 
-    def create_snapshot(self, snapshot_name, disk_name,
-                        description=None, region=None):
-
-        managed_disk = self.compute_client.\
-            disks.get(self.resource_group_name,
-                      disk_name)
-        params = {
-                'location': region or self.region_name,
-                'creation_data': {
-                    'create_option': 'Copy',
-                    'source_uri': managed_disk.id
-                }
-            }
-
-        if description:
-            params['tags'] = {'Description': description}
-
-        snapshot_response = self.compute_client.snapshots.create_or_update(
+    def create_snapshot(self, snapshot_name, params):
+        return self.compute_client.snapshots.create_or_update(
             self.resource_group_name,
             snapshot_name,
             params,
             raw=True
         )
 
-        return snapshot_response
-
     def delete_snapshot(self, snapshot_name):
         async_delete = self.compute_client.snapshots. \
             delete(self.resource_group_name, snapshot_name)
         async_delete.wait()
 
-    def update_snapshot_tags(self, snapshot_name, tags, region=None):
-        snapshot_result = self.compute_client.snapshots.update(
+    def update_snapshot_tags(self, snapshot_name, tags):
+        return self.compute_client.snapshots.update(
             self.resource_group_name,
             snapshot_name,
-            {
-                'tags': tags
-            },
+            {'tags': tags},
             raw=True
         )
-        return snapshot_result
+
+    def get_vm(self, vm_name):
+        return self.compute_client.virtual_machines.get(
+            self.resource_group_name,
+            vm_name
+        )
+
+    def create_or_update_vm(self, vm_name, params):
+        return self.compute_client\
+            .virtual_machines.create_or_update(
+                self.resource_group_name,
+                vm_name,
+                params,
+                raw=True
+            )
+
+    def list_vm(self):
+        return self.compute_client.\
+            virtual_machines.list(self.resource_group_name)

+ 1 - 1
cloudbridge/cloud/providers/azure/helpers.py

@@ -3,7 +3,7 @@ def filter(list_items, filters):
     if filters:
         for obj in list_items:
             for key in filters:
-                if filters[key] in str(getattr(obj, key)):
+                if obj.tags and filters[key] == obj.tags.get(key, ''):
                     filtered_list.append(obj)
 
         return filtered_list

+ 94 - 41
cloudbridge/cloud/providers/azure/mock_azure_client.py

@@ -1,15 +1,18 @@
+import uuid
 from datetime import datetime
 
 from io import BytesIO
 
 from azure.common import AzureException
-from azure.mgmt.compute.models import CreationData, Disk, DiskCreateOption, \
-    Snapshot
+from azure.mgmt.compute.models import CreationData, DataDisk, \
+    Disk, DiskCreateOption, ManagedDiskParameters, \
+    Snapshot, StorageProfile, VirtualMachine
 from azure.mgmt.network.models import NetworkSecurityGroup
 from azure.mgmt.network.models import SecurityRule
 from azure.mgmt.resource.resources.models import ResourceGroup
 from azure.mgmt.storage.models import StorageAccount
-from azure.storage.blob.models import Blob, Container
+from azure.storage.blob.models import Blob, BlobProperties, \
+    Container
 
 from msrestazure.azure_exceptions import CloudError
 
@@ -37,18 +40,22 @@ class MockAzureClient:
     sec_gr1.name = "sg1"
     sec_gr1.id = "/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96/resourceGroups/CloudBridge-Azure'\
     '/providers/Microsoft.Network/networkSecurityGroups/sg1"
+    sec_gr1.tags = None
+    sec_gr1.resource_guid = uuid.uuid4()
     sec_gr1.security_rules = [sg_rule1, sg_rule2]
 
     sec_gr2 = NetworkSecurityGroup()
     sec_gr2.name = "sg2"
     sec_gr2.id = "/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96/resourceGroups/CloudBridge-Azure'\
     '/providers/Microsoft.Network/networkSecurityGroups/sg2"
+    sec_gr2.tags = None
     sec_gr2.security_rules = [sg_rule1, sg_rule2]
 
     sec_gr3 = NetworkSecurityGroup()
     sec_gr3.name = "sg3"
     sec_gr3.id = "/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96/resourceGroups/CloudBridge-Azure'\
     '/providers/Microsoft.Network/networkSecurityGroups/sg3"
+    sec_gr3.tags = {'Name': 'sg3'}
     sec_gr3.security_rules = [sg_rule1, sg_rule2]
 
     security_groups = [sec_gr1, sec_gr2, sec_gr3]
@@ -73,8 +80,12 @@ class MockAzureClient:
     block3.name = "block3"
     block3.content = None
 
+    block4 = Blob()
+    block4.name = "block4"
+    block4.content = None
+
     blocks = {'container1': [block1, block2, block3],
-              'container2': [block1, block2, block3]}
+              'container2': [block1, block2, block3, block4]}
 
     rg = ResourceGroup(location='westus')
     rg.name = "testResourceGroup"
@@ -90,6 +101,10 @@ class MockAzureClient:
     volume1.owner_id = 'ubuntu-intro1'
     volume1.provisioning_state = 'InProgress'
     volume1.tags = {'Name': 'Volume1'}
+    volume1.creation_data.source_uri = \
+        '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96' \
+        '/resourceGroups/CLOUDBRIDGE-AZURE' \
+        '/providers/Microsoft.Compute/snapshots/snapshot1'
 
     volume2 = Disk(location='eastus', creation_data=None)
     volume2.id = '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96' \
@@ -120,7 +135,7 @@ class MockAzureClient:
 
     snapshot2 = Snapshot(location='eastus', creation_data=creation_data)
     snapshot2.name = 'snapshot2'
-    snapshot2.tags = {'Name': 'snapshot1'}
+    snapshot2.tags = None
     snapshot2.disk_size_gb = 2
     snapshot2.creation_data = \
         CreationData(create_option=DiskCreateOption.empty)
@@ -131,10 +146,30 @@ class MockAzureClient:
     snapshot2.account_type = ' Standard_LRS'
 
     snapshots = [snapshot1, snapshot2]
+    vm1 = VirtualMachine(location='eastus')
+    vm1.name = 'VM1'
+
+    vm1.id = '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96'\
+             '/resourceGroups/CLOUDBRIDGE-AZURE'\
+             '/providers/Microsoft.Compute/virtualMachines/VM1'
+    vm1.storage_profile = StorageProfile()
+    data_disk_id = '/subscriptions'\
+                   '/7904d702-e01c-4826-8519-f5a25c866a96' \
+                   '/resourceGroups/CLOUDBRIDGE-AZURE' \
+                   '/providers/Microsoft.Compute/disks/Volume2'
+    data_dik = \
+        DataDisk(managed_disk=ManagedDiskParameters(id=data_disk_id),
+                 lun=0, create_option='attach')
+    vm1.storage_profile.data_disks = [data_dik]
+    virtual_machines = [vm1]
 
     def __init__(self, provider):
         self._provider = provider
 
+    @property
+    def region_name(self):
+        return 'eastus'
+
     def create_security_group(self, name, parameters):
         sg_create = NetworkSecurityGroup()
         sg_create.name = name
@@ -223,8 +258,14 @@ class MockAzureClient:
         self.containers.remove(container)
 
     def create_blob_from_text(self, container_name, blob_name, text):
+        if blob_name == 'block4' and text != '':
+            raise AzureException()
         blob = self.get_blob(container_name, blob_name)
         blob.content = text
+        blob.properties = BlobProperties()
+        blob.properties.content_length = len(text)
+        blob.properties.last_modified = \
+            datetime(year=2017, month=5, day=2)
         return blob
 
     def get_blob(self, container_name, blob_name):
@@ -246,31 +287,37 @@ class MockAzureClient:
         return None
 
     def delete_blob(self, container_name, blob_name):
-        for blob in self.blocks.get(container_name):
-            if blob.name == blob_name:
-                self.blocks.get(container_name).remove(blob)
+        blob = self.get_blob(container_name, blob_name)
+        self.blocks.get(container_name).remove(blob)
 
     def create_blob_from_file(self, container_name, blob_name, file_path):
+        if blob_name == 'block4':
+            raise AzureException()
+
         blob = self.get_blob(container_name, blob_name)
         blob.content = file_path
 
     def get_blob_url(self, container_name, blob_name):
         return 'https://cloudbridgeazure.blob.core.windows.net/vhds/block1'
 
-    def create_empty_disk(self, disk_name, size,
-                          region=None, snapshot_id=None, description=None):
+    def create_empty_disk(self, disk_name, params):
         volume = Disk(location='eastus', creation_data=None)
         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.disk_size_gb = 30
         volume.creation_data = CreationData(
             create_option=DiskCreateOption.empty)
         volume.time_created = datetime(year=2017, month=5, day=2)
         volume.location = 'eastus'
         volume.provisioning_state = 'Succeeded'
-        volume.tags = {'Name': disk_name, 'Description': description}
+        volume.tags = params.get('tags', None)
+        if disk_name.startswith('attach'):
+            volume.owner_id = \
+                '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96'\
+                '/resourceGroups/CLOUDBRIDGE-AZURE'\
+                '/providers/Microsoft.Compute/virtualMachines/VM1'
         self.volumes.append(volume)
         return volume
 
@@ -290,26 +337,6 @@ class MockAzureClient:
         self.volumes.remove(disk)
         return True
 
-    def attach_disk(self, vm_name, disk_name, disk_id):
-        disk = self.get_disk(disk_name)
-        if disk.owner_id:
-            response = Response()
-            response.status_code = 404
-            raise CloudError(response=response,
-                             error='Resource already in use')
-
-        disk.owner_id = vm_name
-
-    def detach_disk(self, disk_id):
-        for d in self.volumes:
-            if d.id == disk_id and not d.owner_id:
-                response = Response()
-                response.status_code = 404
-                raise CloudError(response=response,
-                                 error='Resource already available')
-            elif d.id == disk_id:
-                d.owner_id = None
-
     def get_storage_account(self, storage_account_name):
         if storage_account_name == 'cloudbridgeazure':
             response = Response()
@@ -328,13 +355,12 @@ class MockAzureClient:
     def update_disk_tags(self, disk_name, tags):
         pass
 
-    def create_snapshot(self, snapshot_name, disk_name,
-                        description=None, region=None):
+    def create_snapshot(self, snapshot_name, params):
         snapshot = Snapshot(location='eastus', creation_data=None)
         snapshot.id = '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96' \
                       '/resourceGroups/cloudbridge-azure' \
                       '/providers/Microsoft.Compute/Snapshots/{0}'.format(
-                        disk_name)
+                        snapshot_name)
         snapshot.name = snapshot_name
         snapshot.disk_size_gb = 30
         snapshot.creation_data = \
@@ -344,9 +370,8 @@ class MockAzureClient:
             '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96' \
             '/resourceGroups/CloudBridge-Azure/providers' \
             '/Microsoft.Compute/disks/{0}'.format(
-                disk_name)
-        if description:
-            snapshot.tags = {'Description': description}
+                snapshot_name)
+        snapshot.tags = params.get('tags', None)
         self.snapshots.append(snapshot)
         return snapshot
 
@@ -369,7 +394,7 @@ class MockAzureClient:
         self.snapshots.remove(snapshot)
         return True
 
-    def create_snapshot_disk(self, disk_name, snapshot_id, region=None):
+    def create_snapshot_disk(self, disk_name, params):
         volume = Disk(location='eastus', creation_data=None)
         volume.id = '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96' \
                     '/resourceGroups/cloudbridge-azure/providers' \
@@ -379,11 +404,39 @@ class MockAzureClient:
         volume.disk_size_gb = 50
         volume.creation_data = CreationData(
             create_option=DiskCreateOption.copy,
-            source_uri=snapshot_id)
+            source_uri=params.get('creation_data').get('source_uri'))
         volume.time_created = '01-01-2017'
-        volume.tags = {'Name': disk_name}
+        volume.tags = params.get('tags', None)
         self.volumes.append(volume)
         return volume
 
     def list_snapshots(self):
         return self.snapshots
+
+    def get_vm(self, vm_name):
+        for virtual_machine in self.virtual_machines:
+            if virtual_machine.name == vm_name:
+                return virtual_machine
+
+        response = Response()
+        response.status_code = 404
+        raise CloudError(response=response, error='Resource Not found')
+
+    def create_or_update_vm(self, vm_name, params):
+        for data_disk in params.storage_profile.data_disks:
+            if isinstance(data_disk, dict):
+                disk_id = data_disk.get('managed_disk').get('id')
+                lun = data_disk.get('lun')
+                create_option = data_disk.get('create_option')
+                managed_disk = \
+                    ManagedDiskParameters(id=disk_id)
+                params.storage_profile.data_disks.remove(data_disk)
+                params.storage_profile.\
+                    data_disks\
+                    .append(DataDisk(managed_disk=managed_disk,
+                            lun=lun, create_option=create_option))
+
+        return params
+
+    def list_vm(self):
+        return self.virtual_machines

+ 76 - 27
cloudbridge/cloud/providers/azure/resources.py

@@ -88,6 +88,21 @@ class AzureSecurityGroup(BaseSecurityGroup):
     def network_id(self):
         return self._security_group.resource_guid
 
+    @property
+    def resource_name(self):
+        return self._security_group.name
+
+    @property
+    def name(self):
+        return self._security_group.tags.get('Name', self._security_group.name)
+
+    @name.setter
+    def name(self, value):
+        self._security_group.tags.update(Name=value)
+        self._provider.azure_client. \
+            update_security_group_tags(self.resource_name,
+                                       self._security_group.tags)
+
     @property
     def description(self):
         return self._security_group.tags.get('Description', None)
@@ -95,9 +110,9 @@ class AzureSecurityGroup(BaseSecurityGroup):
     @description.setter
     def description(self, value):
         self._security_group.tags.update(Description=value)
-        print(self._security_group.tags)
         self._provider.azure_client.\
-            update_security_group_tags(self.name, self._security_group.tags)
+            update_security_group_tags(self.resource_name,
+                                       self._security_group.tags)
 
     @property
     def rules(self):
@@ -143,7 +158,6 @@ class AzureSecurityGroup(BaseSecurityGroup):
         rule = self.get_rule(ip_protocol, from_port,
                              to_port, cidr_ip, src_group)
         if not rule:
-            security_group = self._security_group.name
             # resource_group = self._provider.resource_group
             count = len(self.rules) + 1
             rule_name = "Rule - " + str(count)
@@ -162,7 +176,7 @@ class AzureSecurityGroup(BaseSecurityGroup):
                               destination_address_prefix,
                           "access": access, "direction": direction}
             result = self._provider.azure_client. \
-                create_security_group_rule(security_group,
+                create_security_group_rule(self.resource_name,
                                            rule_name, parameters)
             self._security_group.security_rules.append(result)
             return AzureSecurityGroupRule(self._provider, result, self)
@@ -432,6 +446,10 @@ class AzureVolume(BaseVolume):
     def id(self):
         return self._volume.id
 
+    @property
+    def resource_name(self):
+        return self._volume.name
+
     @property
     def name(self):
         """
@@ -439,7 +457,7 @@ class AzureVolume(BaseVolume):
 
         .. note:: an instance must have a (case sensitive) tag ``Name``
         """
-        return self._volume.name
+        return self._volume.tags.get('Name', self._volume.name)
 
     @name.setter
     # pylint:disable=arguments-differ
@@ -448,7 +466,10 @@ class AzureVolume(BaseVolume):
         Set the volume name.
         """
         # self._volume.name = value
-        pass
+        self._volume.tags.update(Name=value)
+        self._provider.azure_client.\
+            update_disk_tags(self.resource_name,
+                             self._volume.tags)
 
     @property
     def description(self):
@@ -458,7 +479,7 @@ class AzureVolume(BaseVolume):
     def description(self, value):
         self._volume.tags.update(Description=value)
         self._provider.azure_client.\
-            update_disk_tags(self._url_params.get(VOLUME_NAME),
+            update_disk_tags(self.resource_name,
                              self._volume.tags)
 
     @property
@@ -499,8 +520,19 @@ class AzureVolume(BaseVolume):
                 Instance) else instance
             params = azure_helpers.parse_url(INSTANCE_RESOURCE_ID,
                                              instance_id)
-            self._provider.azure_client.attach_disk(params.get(VM_NAME),
-                                                    self.name, self.id)
+
+            vm = self._provider.azure_client.get_vm(params.get(VM_NAME))
+
+            vm.storage_profile.data_disks.append({
+                'lun': len(vm.storage_profile.data_disks),
+                'name': self.resource_name,
+                'create_option': 'attach',
+                'managed_disk': {
+                    'id': self.id
+                }
+            })
+            self._provider.azure_client\
+                .create_or_update_vm(params.get(VM_NAME), vm)
             return True
         except CloudError:
             return False
@@ -509,11 +541,24 @@ class AzureVolume(BaseVolume):
         """
         Detach this volume from an instance.
         """
-        try:
-            self._provider.azure_client.detach_disk(self.id)
+        virtual_machine = None
+        for index, vm in enumerate(
+                self._provider.azure_client.list_vm()):
+            for item in vm.storage_profile.data_disks:
+                if item.managed_disk and item.managed_disk.id == self.id:
+                    vm.storage_profile.data_disks.remove(item)
+                    virtual_machine = vm
+                    break
+            if virtual_machine:
+                break
+
+        if virtual_machine:
+            self._provider.azure_client.create_or_update_vm(
+                virtual_machine.name,
+                virtual_machine
+            )
             return True
-        except CloudError:
-            return False
+        return False
 
     def create_snapshot(self, name, description=None):
         """
@@ -527,7 +572,7 @@ class AzureVolume(BaseVolume):
         """
         try:
             self._provider.azure_client.\
-                delete_disk(self._url_params.get(VOLUME_NAME))
+                delete_disk(self.resource_name)
             return True
         except CloudError:
             return False
@@ -543,9 +588,8 @@ class AzureVolume(BaseVolume):
         for its latest state.
         """
         try:
-            print('Volume status ' + self._status)
             self._volume = self._provider.azure_client.\
-                get_disk(self._url_params.get(VOLUME_NAME))
+                get_disk(self.resource_name)
             self.update_status()
         except (CloudError, ValueError):
             # The volume no longer exists and cannot be refreshed.
@@ -578,6 +622,10 @@ class AzureSnapshot(BaseSnapshot):
     def id(self):
         return self._snapshot.id
 
+    @property
+    def resource_name(self):
+        return self._snapshot.name
+
     @property
     def name(self):
         """
@@ -585,7 +633,7 @@ class AzureSnapshot(BaseSnapshot):
 
         .. note:: an instance must have a (case sensitive) tag ``Name``
         """
-        return self._snapshot.name
+        return self._snapshot.tags.get('Name', self._snapshot.name)
 
     @name.setter
     # pylint:disable=arguments-differ
@@ -594,7 +642,10 @@ class AzureSnapshot(BaseSnapshot):
         Set the snapshot name.
         """
         # self._snapshot.name = value
-        pass
+        self._snapshot.tags.update(Name=value)
+        self._provider.azure_client. \
+            update_snapshot_tags(self.resource_name,
+                                 self._snapshot.tags)
 
     @property
     def description(self):
@@ -604,7 +655,8 @@ class AzureSnapshot(BaseSnapshot):
     def description(self, value):
         self._snapshot.tags.update(Description=value)
         self._provider.azure_client.\
-            update_snapshot_tags(self.name, self._snapshot.tags)
+            update_snapshot_tags(self.resource_name,
+                                 self._snapshot.tags)
 
     @property
     def size(self):
@@ -630,7 +682,7 @@ class AzureSnapshot(BaseSnapshot):
         """
         try:
             self._snapshot = self._provider.azure_client.\
-                get_snapshot(self.name)
+                get_snapshot(self.resource_name)
             self._status = self._snapshot.provisioning_state
         except (CloudError, ValueError):
             # The snapshot no longer exists and cannot be refreshed.
@@ -642,7 +694,7 @@ class AzureSnapshot(BaseSnapshot):
         Delete this snapshot.
         """
         try:
-            self._provider.azure_client.delete_snapshot(self.name)
+            self._provider.azure_client.delete_snapshot(self.resource_name)
             return True
         except CloudError:
             return False
@@ -652,9 +704,6 @@ class AzureSnapshot(BaseSnapshot):
         """
         Create a new Volume from this Snapshot.
         """
-        self._provider.azure_client.\
-            create_snapshot_disk(self.name + '_disk',
-                                 self.id, region=placement)
-        azure_vol = self._provider.azure_client.get_disk(self.name + '_disk')
-        cb_vol = AzureVolume(self._provider, azure_vol)
-        return cb_vol
+        return self._provider.block_store.volumes.\
+            create(self.resource_name, self.size,
+                   zone=placement, snapshot=self)

+ 52 - 11
cloudbridge/cloud/providers/azure/services.py

@@ -1,4 +1,5 @@
 import logging
+import uuid
 
 from azure.common import AzureException
 
@@ -73,10 +74,11 @@ class AzureSecurityGroupService(BaseSecurityGroupService):
         return ClientPagedResultList(self.provider, sgs, limit, marker)
 
     def create(self, name, description, network_id):
-        parameters = {"location": self.provider.region_name}
+        parameters = {"location": self.provider.region_name,
+                      'tags': {'Name': name}}
 
         if description:
-            parameters['tags'] = {'Description': description}
+            parameters['tags'].update(Description=description)
 
         sg = self.provider.azure_client.create_security_group(name, parameters)
         cb_sg = AzureSecurityGroup(self.provider, sg)
@@ -87,7 +89,7 @@ class AzureSecurityGroupService(BaseSecurityGroupService):
         """
         Searches for a security group by a given list of attributes.
         """
-        filters = {'name': name}
+        filters = {'Name': name}
         sgs = [AzureSecurityGroup(self.provider, security_group)
                for security_group in azure_helpers.filter(
                 self.provider.azure_client.list_security_group(), filters)]
@@ -181,7 +183,7 @@ class AzureVolumeService(BaseVolumeService):
         """
         Searches for a volume by a given list of attributes.
         """
-        filters = {'name': name}
+        filters = {'Name': name}
         cb_vols = [AzureVolume(self.provider, volume)
                    for volume in azure_helpers.filter(
                 self.provider.azure_client.list_disks(), filters)]
@@ -198,9 +200,34 @@ class AzureVolumeService(BaseVolumeService):
         zone_id = zone.id if isinstance(zone, PlacementZone) else zone
         snapshot_id = snapshot.id if isinstance(
             snapshot, Snapshot) and snapshot else snapshot
-        self.provider.azure_client.create_empty_disk(
-            name, size, zone_id, snapshot_id, description=description)
-        azure_vol = self.provider.azure_client.get_disk(name)
+        disk_name = "{0}-{1}".format(name, uuid.uuid4().hex[:6])
+        tags = {'Name': name}
+        if description:
+            tags.update(Description=description)
+        if snapshot_id:
+            params = {
+                'location': zone_id or self.provider.azure_client.region_name,
+                'creation_data': {
+                    'create_option': 'copy',
+                    'source_uri': snapshot_id
+                },
+                'tags': tags
+            }
+
+            self.provider.azure_client.create_snapshot_disk(disk_name, params)
+
+        else:
+            params = {
+                'location': zone_id or self.provider.azure_client.region_name,
+                'disk_size_gb': size,
+                'creation_data': {
+                  'create_option': 'empty'
+                  },
+                'tags': tags}
+
+            self.provider.azure_client.create_empty_disk(disk_name, params)
+
+        azure_vol = self.provider.azure_client.get_disk(disk_name)
         cb_vol = AzureVolume(self.provider, azure_vol)
 
         return cb_vol
@@ -236,11 +263,25 @@ class AzureSnapshotService(BaseSnapshotService):
 
     def create(self, name, volume, description=None):
         volume_id = volume.id if isinstance(volume, Volume) else volume
-        params = azure_helpers.parse_url(VOLUME_RESOURCE_ID, volume_id)
+
+        tags = {'Name': name}
+        snapshot_name = "{0}-{1}".format(name, uuid.uuid4().hex[:6])
+
+        if description:
+            tags.update(Description=description)
+
+        params = {
+            'location': self.provider.azure_client.region_name,
+            'creation_data': {
+                'create_option': 'Copy',
+                'source_uri': volume_id
+            },
+            'tags': tags
+        }
+
         self.provider.azure_client. \
-            create_snapshot(name, params.get(VOLUME_NAME),
-                            description=description)
-        azure_snap = self.provider.azure_client.get_snapshot(name)
+            create_snapshot(snapshot_name, params)
+        azure_snap = self.provider.azure_client.get_snapshot(snapshot_name)
         cb_snap = AzureSnapshot(self.provider, azure_snap)
 
         return cb_snap

+ 12 - 8
integration_test/test_integration_azure_volume_service.py

@@ -6,8 +6,8 @@ import azure_integration_test.helpers as helpers
 class AzureIntegrationVolumeServiceTestCase(helpers.ProviderTestBase):
     @helpers.skipIfNoService(['block_store'])
     def test_azure_volume_service(self):
-        volume_name = '{0}'.format(uuid.uuid4())
-        snapshot_name = '{0}'.format(uuid.uuid4())
+        volume_name = '{0}'.format(uuid.uuid4().hex[:6])
+        snapshot_name = '{0}'.format(uuid.uuid4().hex[:6])
 
         volume_list_before_create = self.provider.block_store.volumes.list()
         print(str(len(volume_list_before_create)))
@@ -32,16 +32,20 @@ class AzureIntegrationVolumeServiceTestCase(helpers.ProviderTestBase):
         print("Find Volume  - " + str(volume))
         self.assertEqual(
             len(volume_find), 1)
-        # volume.attach('/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96/resourceGroups/CloudBridge-Azure/providers/Microsoft.Compute/virtualMachines/ubuntu-intro2')
+        instance_id = '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96' \
+                      '/resourceGroups/CloudBridge-Azure/providers'\
+                      '/Microsoft.Compute/virtualMachines/ubuntu-intro1'
+        volume.attach(instance_id)
         # TODO: Add logic to verify that disk is attached to instance
 
-        # volume.detach()
+        volume.detach()
         # TODO: Add logic to verify that disk is not in use
 
-        with self.assertRaises(NotImplementedError):
-            volume.create_snapshot(snapshot_name)
-        # self.assertTrue(snapshot is not None,
-        # 'Snapshot {0} not created'.format(snapshot_name))
+        snapshot = volume.create_snapshot(snapshot_name)
+        self.assertTrue(snapshot is not None,
+                        'Snapshot {0} not created'.format(snapshot_name))
+
+        snapshot.delete()
 
         volume.refresh()
         self.assertTrue(volume.id == volume_id,

+ 8 - 8
test/test_azure_helpers.py

@@ -16,29 +16,29 @@ class AzureHelpersTestCase(ProviderTestBase):
 
     def test_filter_matched(self):
         ex1 = Expando()
-        ex1.name = 'test'
+        ex1.tags = {'Name': 'test'}
 
         ex2 = Expando()
-        ex2.name = 'abc'
+        ex2.tags = {'Name': 'abc'}
 
-        result = azure_helpers.filter([ex1, ex2], {'name': 'test'})
+        result = azure_helpers.filter([ex1, ex2], {'Name': 'test'})
         self.assertTrue(len(result) == 1, 'Result count should be one')
 
     def test_filter_not_matched(self):
         ex1 = Expando()
-        ex1.name = 'pqr'
+        ex1.tags = {'Name': 'pqr'}
 
         ex2 = Expando()
-        ex2.name = 'abc'
-        result = azure_helpers.filter([ex1, ex2], {'name': 'test123'})
+        ex2.tags = {'Name': 'abc'}
+        result = azure_helpers.filter([ex1, ex2], {'Name': 'test123'})
         self.assertTrue(len(result) == 0, 'Result count should be zero')
 
     def test_filter_None(self):
         ex1 = Expando()
-        ex1.name = 'pqr'
+        ex1.tags = {'Name': 'test'}
 
         ex2 = Expando()
-        ex2.name = 'abc'
+        ex2.tags = {'Name': 'abc'}
         result = azure_helpers.filter([ex1, ex2], None)
         self.assertTrue(len(result) == 2, 'Result count should be two')
 

+ 27 - 5
test/test_azure_object_store_service.py

@@ -9,6 +9,7 @@ class AzureObjectStoreServiceTestCase(ProviderTestBase):
         print("Create - " + str(container))
         self.assertEqual(
             str(container), "<CB-AzureBucket: container3>")
+        self.assertIsNotNone(container.id)
 
     @helpers.skipIfNoService(['object_store'])
     def test_azure_bucket_list(self):
@@ -55,15 +56,21 @@ class AzureObjectStoreServiceTestCase(ProviderTestBase):
         print("Bucket delete - " + str(contDel))
         self.assertEqual(
             contDel, True)
+        contDel = cont.delete()
+        self.assertEqual(
+            contDel, False)
 
     @helpers.skipIfNoService(['object_store'])
     def test_azure_bucket_create_object(self):
         containers = self.provider.object_store.find("container1")
         cont = containers[0]
-        contDel = cont.create_object("block1")
-        print("Create object  - " + str(contDel))
+        obj = cont.create_object("block1")
+        self.assertIsNotNone(obj.id)
+        self.assertIsNotNone(obj.size)
+        self.assertIsNotNone(obj.last_modified)
+        print("Create object  - " + str(obj))
         self.assertEqual(
-            str(contDel), '<CB-AzureBucketObject: block1>')
+            str(obj), '<CB-AzureBucketObject: block1>')
 
     @helpers.skipIfNoService(['object_store'])
     def test_azure_bucket_object_exists__internalE(self):
@@ -90,7 +97,7 @@ class AzureObjectStoreServiceTestCase(ProviderTestBase):
         contDel = cont.list()
         print("List object  - " + str(contDel))
         self.assertEqual(
-            len(contDel), 2)
+            len(contDel), 3)
 
     @helpers.skipIfNoService(['object_store'])
     def test_azure_bucket_object_get(self):
@@ -139,7 +146,9 @@ class AzureObjectStoreServiceTestCase(ProviderTestBase):
         block = blocks[0]
         block.delete()
         self.assertEqual(
-            len(cont.list()), 2)
+            len(cont.list()), 3)
+        deleted = block.delete()
+        self.assertEqual(deleted, False)
 
     @helpers.skipIfNoService(['object_store'])
     def test_azure_bucket_object_upload_from_file(self):
@@ -151,6 +160,19 @@ class AzureObjectStoreServiceTestCase(ProviderTestBase):
         self.assertEqual(
             block.iter_content().getvalue(), b'blob2Content')
 
+    @helpers.skipIfNoService(['object_store'])
+    def test_azure_bucket_object_upload_exception(self):
+        containers = self.provider.object_store.find("container2")
+        cont = containers[0]
+        blob = cont.create_object('block4')
+        uploaded = blob.upload_from_file('E:\\blob2Content.txt')
+        self.assertEqual(uploaded, False)
+
+        uploaded = blob.upload('blob2Content')
+        self.assertEqual(uploaded, False)
+
+        blob.delete()
+
     @helpers.skipIfNoService(['object_store'])
     def test_azure_bucket_object_generate_url(self):
         containers = self.provider.object_store.find("container2")

+ 5 - 1
test/test_azure_security_service.py

@@ -24,6 +24,7 @@ class AzureSecurityServiceTestCase(ProviderTestBase):
         print("Create - " + str(sg))
         self.assertEqual(name, sg.name)
         sg.description = name
+        sg.name = 'NewName'
         self.assertEqual(name, sg.description)
         self.provider.security.security_groups.delete(
             "/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96'\
@@ -33,7 +34,7 @@ class AzureSecurityServiceTestCase(ProviderTestBase):
 
     @helpers.skipIfNoService(['security.security_groups'])
     def test_azure_security_group_find_exists(self):
-        sgl = self.provider.security.security_groups.find("sg")
+        sgl = self.provider.security.security_groups.find("sg3")
         for sg in sgl:
             self.assertTrue("sg" in sg.name)
         self.assertTrue(sgl.total_results > 0)
@@ -142,6 +143,9 @@ class AzureSecurityServiceTestCase(ProviderTestBase):
         rule = cb.to_json()
         print("Get Rule -  " + str(rule))
         self.assertIsNotNone(rule)
+        cb = list.data[1]
+        rule = cb.to_json()
+        self.assertIsNotNone(rule)
 
     @helpers.skipIfNoService(['security.security_groups'])
     def test_azure_security_group_rule_to_json(self):

+ 23 - 25
test/test_azure_volume_service.py

@@ -23,12 +23,12 @@ class AzureVolumeServiceTestCase(ProviderTestBase):
         volume.name = 'newname'
 
         volume = self.provider.block_store.volumes.get(
-            "/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96/resourceGroups/cloudbridge-azure/providers'\
-            '/Microsoft.Compute/disks/MyVolume")
+            volume.id)
         volume.description = 'My Volume desc'
         print("Get Volume  - " + str(volume))
         self.assertTrue(
-            volume.name == "MyVolume", "Volume name should be MyVolume")
+            volume.description == "My Volume desc",
+            "Volume description should be My Volume desc")
 
         volume.delete()
 
@@ -54,33 +54,28 @@ class AzureVolumeServiceTestCase(ProviderTestBase):
             volume1 is None, "Volume still exists")
 
     @helpers.skipIfNoService(['block_store.volumes'])
-    def test_azure_volume_attach(self):
+    def test_azure_volume_attach_and_detach(self):
         volume = self.provider.block_store.volumes.create(
-            "MyVolume", 1, description='My volume')
+            "attach", 1, description='My volume')
         self.assertTrue(
-            volume.name == "MyVolume", "Volume name should be MyVolume")
-        attached = volume.attach("/subscriptions'\
-        '/7904d702-e01c-4826-8519-f5a25c866a96'\
-        '/resourceGroups/CloudBridge-Azure/providers'\
-        '/Microsoft.Compute/virtualMachines/ubuntu-intro1")
+            volume.name == "attach", "Volume name should be MyVolume")
+        instance_id = '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96'\
+                      '/resourceGroups/CLOUDBRIDGE-AZURE'\
+                      '/providers/Microsoft.Compute/virtualMachines/VM1'
+        attached = volume.attach(instance_id)
 
         self.assertEqual(attached, True)
-
-        attach_volume = volume.attach("/subscriptions'\
-        '/7904d702-e01c-4826-8519-f5a25c866a96'\
-        '/resourceGroups/CloudBridge-Azure/providers'\
-        '/Microsoft.Compute/virtualMachines/ubuntu-intro1")
+        self.assertIsNotNone(volume.attachments)
+        instance_id = instance_id + '1'
+        attach_volume = volume.attach(instance_id)
         self.assertEqual(attach_volume, False)
 
-        volume.delete()
+        detached = volume.detach()
+        self.assertEqual(detached, True)
+
+        detached = volume.detach()
+        self.assertEqual(detached, False)
 
-    @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'])
@@ -106,9 +101,12 @@ class AzureVolumeServiceTestCase(ProviderTestBase):
 
     @helpers.skipIfNoService(['block_store.volumes'])
     def test_azure_volume_find(self):
-        volumes = self.provider.block_store.volumes.find("Volume")
+        volumes = self.provider.block_store.volumes.find("Volume1")
+        print(len(volumes))
+        print('after find')
         self.assertTrue(
-            len(volumes) == 2, "Volume should not be available")
+            len(volumes) == 1, "Volume should not be available")
+        self.assertIsNotNone(volumes[0].source)
 
     @helpers.skipIfNoService(['block_store.volumes'])
     def test_azure_volume_find_ifNotExist(self):