Quellcode durchsuchen

Implemented create volume method

vikramdoda vor 9 Jahren
Ursprung
Commit
7267420f82

+ 40 - 0
cloudbridge/cloud/providers/azure/azure_client.py

@@ -41,6 +41,10 @@ class AzureClient(object):
     def storage_account_name(self):
         return self._config.get('azure_storage_account_name')
 
+    @property
+    def region_name(self):
+        return self._config.get('azure_region_name')
+
     @property
     def storage_client(self):
         return self._storage_client
@@ -142,3 +146,39 @@ class AzureClient(object):
 
     def get_blob_content(self, container_name, blob_name):
         return self.blob_service.get_blob_to_text(container_name, blob_name)
+
+    def create_empty_disk(self, disk_name, size, region=None, snapshot_id=None):
+        if snapshot_id:
+            return self.create_snapshot_disk(disk_name, snapshot_id, region)
+
+        async_creation = self.compute_client.disks.create_or_update(
+            self.resource_group_name,
+            disk_name,
+            {
+                'location': region or self.region_name,
+                'disk_size_gb': size,
+                'creation_data': {
+                    'create_option': 'empty'
+                }
+            }
+        )
+        disk_resource = async_creation.result()
+        return disk_resource
+
+    def create_snapshot_disk(self, disk_name, snapshot_id, region=None):
+        async_creation = 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
+                }
+            }
+        )
+        disk_resource = async_creation.result()
+        return disk_resource
+
+    def get_disk(self, disk_name):
+        return self.compute_client.disks.get(self.resource_group_name, disk_name)

+ 4 - 3
cloudbridge/cloud/providers/azure/provider.py

@@ -6,7 +6,8 @@ from cloudbridge.cloud.interfaces import TestMockHelperMixin
 
 from cloudbridge.cloud.providers.azure.azure_client import AzureClient
 from cloudbridge.cloud.providers.azure.mock_azure_client import MockAzureClient
-from cloudbridge.cloud.providers.azure.services import AzureSecurityService, AzureObjectStoreService
+from cloudbridge.cloud.providers.azure.services import AzureSecurityService, AzureObjectStoreService, \
+    AzureBlockStoreService
 
 log = logging.getLogger(__name__)
 
@@ -58,6 +59,7 @@ class AzureCloudProvider(BaseCloudProvider):
 
         self._security = AzureSecurityService(self)
         self._object_store = AzureObjectStoreService(self)
+        self._block_store = AzureBlockStoreService(self)
 
     @property
     def compute(self):
@@ -75,8 +77,7 @@ class AzureCloudProvider(BaseCloudProvider):
 
     @property
     def block_store(self):
-        raise NotImplementedError(
-            "AzureCloudProvider does not implement this service")
+        return self._block_store
 
     @property
     def object_store(self):

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

@@ -5,8 +5,39 @@ import inspect
 import json
 from datetime import datetime
 
+from msrestazure.azure_exceptions import CloudError
+
 from cloudbridge.cloud.base.resources import BaseBucket, BaseSecurityGroup, BaseSecurityGroupRule, BaseBucketObject, \
-    ClientPagedResultList
+    ClientPagedResultList, BaseVolume, BaseAttachmentInfo, BaseInstance, BaseSnapshot
+from cloudbridge.cloud.interfaces import VolumeState, SnapshotState, InstanceState
+
+NETWORK_RESOURCE_ID = '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{virtualNetworkName}'
+IMAGE_RESOURCE_ID =  '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/images/{imageName}'
+INSTANCE_RESOURCE_ID = '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/virtualMachines/{vmName}'
+VOLUME_RESOURCE_ID = '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/disks/{diskName}'
+SNAPSHOT_RESOURCE_ID = '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/snapshots/{snapshotName}'
+NETWORK_SECURITY_GROUP_RESOURCE_ID = '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/networkSecurityGroups/{networkSecurityGroupName}'
+NETWORK_SECURITY_RULE_RESOURCE_ID = '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/networkSecurityGroups/{networkSecurityGroupName}/securityRules/{securityRuleName}'
+SUBNET_RESOURCE_ID = '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{virtualNetworkName}/subnets/{subnetName}'
+PUBLIC_IP_RESOURCE_ID = '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/publicIPAddresses/{publicIpAddressName}'
+ROUTE_TABLE_RESOURCE_ID = '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/routeTables/{routeTableName}'
+ROUTE_RESOURCE_ID = '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/routeTables/{routeTableName}/routes/{routeName}'
+NETWORK_INTERFACE_RESOURCE_ID = '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/networkInterfaces/{networkInterfaceName}'
+
+RESOURCE_GROUP_NAME='resourceGroupName'
+SUBSCRIPTION_ID='subscriptionId'
+NETWORK_NAME='virtualNetworkName'
+IMAGE_NAME='imageName'
+VM_NAME='vmName'
+VOLUME_NAME ='diskName'
+SNAPSHOT_NAME ='snapshotName'
+SECURITY_GROUP_NAME='networkSecurityGroupName'
+SECURITY_GROUP_RULE_NAME ='securityRuleName'
+SUBNET_NAME = 'subnetName'
+PUBLIC_IP_NAME = 'publicIpAddressName'
+ROUTE_TABLE_NAME = 'routeTableName'
+ROUTE_NAME = 'routeName'
+NETWORK_INTERFACE_NAME ='networkInterfaceName'
 
 
 class AzureSecurityGroup(BaseSecurityGroup):
@@ -281,3 +312,131 @@ class AzureBucket(BaseBucket):
         Determine if an object with given name exists in this bucket.
         """
         return True if self.get(name) else False
+
+
+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
+    }
+
+    def __init__(self, provider, volume):
+        super(AzureVolume, self).__init__(provider)
+        self._volume = volume
+        self._url_params= TemplateUrlParser.parse(VOLUME_RESOURCE_ID,volume.id)
+
+    @property
+    def id(self):
+        return self._volume.id
+
+    @property
+    def name(self):
+        """
+        Get the volume name.
+
+        .. note:: an instance must have a (case sensitive) tag ``Name``
+        """
+        return self._volume.name
+
+    @name.setter
+    # pylint:disable=arguments-differ
+    def name(self, value):
+        """
+        Set the volume name.
+        """
+        self._volume.name = value
+
+    @property
+    def description(self):
+        return None
+
+    @description.setter
+    def description(self, value):
+        pass
+
+    @property
+    def size(self):
+        return self._volume.disk_size_gb
+
+    @property
+    def create_time(self):
+        return self._volume.time_created
+
+    @property
+    def zone_id(self):
+        return self._volume.location
+
+    @property
+    def source(self):
+        return None
+
+    @property
+    def attachments(self):
+        return None
+
+    def attach(self, instance, device=None):
+        pass
+
+    def detach(self, force=False):
+        pass
+
+    def create_snapshot(self, name, description=None):
+        pass
+
+    def delete(self):
+        pass
+
+    @property
+    def state(self):
+        return AzureVolume.VOLUME_STATE_MAP.get(
+            self._volume.provisioning_state, VolumeState.UNKNOWN)
+
+    def refresh(self):
+        pass
+
+
+class AzureInstance(BaseInstance):
+
+    def __init__(self, provider, vm_instace):
+        super(AzureInstance, self).__init__(provider)
+        self._vm = vm_instace
+        self._url_params = TemplateUrlParser.parse(INSTANCE_RESOURCE_ID,vm_instace.id)
+
+    @property
+    def id(self):
+        """
+        Get the instance identifier.
+        """
+        return self._vm.id
+
+
+class AzureSnapshot(BaseSnapshot):
+
+    def __init__(self, provider, snapshot):
+        super(AzureSnapshot, self).__init__(provider)
+        self._snapshot = snapshot
+        self._url_params = TemplateUrlParser.parse(SNAPSHOT_RESOURCE_ID,snapshot.id)
+
+    @property
+    def id(self):
+        return self._snapshot.id
+
+
+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

+ 46 - 2
cloudbridge/cloud/providers/azure/services.py

@@ -1,7 +1,14 @@
 import logging
 
+from cloudbridge.cloud.interfaces.resources import PlacementZone
+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, AzureSnapshot
+
 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
 
 from .resources import AzureBucket, AzureSecurityGroup
 
@@ -101,4 +108,41 @@ class AzureObjectStoreService(BaseObjectStoreService):
 
     def create(self, name, location=None):
         object_store = self.provider.azure_client.create_container(name)
-        return AzureBucket(self.provider, object_store)
+        return AzureBucket(self.provider, object_store)
+
+
+class AzureBlockStoreService(BaseBlockStoreService):
+    def __init__(self, provider):
+        super(AzureBlockStoreService, self).__init__(provider)
+
+        # Initialize provider services
+        self._volume_svc = AzureVolumeService(self.provider)
+        #self._snapshot_svc = AzureSnapshotService(self.provider)
+
+    @property
+    def volumes(self):
+        return self._volume_svc
+
+    @property
+    def snapshots(self):
+        pass
+
+class AzureVolumeService(BaseVolumeService):
+
+    def __init__(self, provider):
+        super(AzureVolumeService, self).__init__(provider)
+
+    def get(self, volume_id):
+        raise NotImplementedError('AzureVolumeService not imeplemented this method')
+
+    def find(self, name, limit=None, marker=None):
+        raise NotImplementedError('AzureVolumeService not imeplemented this method')
+
+    def list(self, limit=None, marker=None):
+        raise NotImplementedError('AzureVolumeService not imeplemented this method')
+
+    def create(self, name, size, zone=None, snapshot=None, description=None):
+        region = zone.id if isinstance(zone, PlacementZone) else zone
+        snapshot_id = snapshot.id if isinstance(snapshot, AzureSnapshot) and snapshot else snapshot
+        volume =  self.provider.azure_client.create_empty_disk(name, size, region, snapshot_id)
+        return AzureVolume(self.provider, volume)