You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@libcloud.apache.org by an...@apache.org on 2017/08/11 05:00:43 UTC

[01/20] libcloud git commit: FAM-928 renamings

Repository: libcloud
Updated Branches:
  refs/heads/trunk 57fe73347 -> c7e81a5f6


FAM-928 renamings


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/39feeebc
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/39feeebc
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/39feeebc

Branch: refs/heads/trunk
Commit: 39feeebc4f03dde4cd32db20fe3bdc63310103be
Parents: 2ade41d
Author: mermoldy <s....@scalr.com>
Authored: Wed May 31 16:00:51 2017 +0300
Committer: Anthony Shaw <an...@apache.org>
Committed: Fri Aug 11 14:59:31 2017 +1000

----------------------------------------------------------------------
 libcloud/compute/drivers/azure_arm.py | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/39feeebc/libcloud/compute/drivers/azure_arm.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/azure_arm.py b/libcloud/compute/drivers/azure_arm.py
index d0de32f..bd36731 100644
--- a/libcloud/compute/drivers/azure_arm.py
+++ b/libcloud/compute/drivers/azure_arm.py
@@ -887,7 +887,7 @@ class AzureNodeDriver(NodeDriver):
         return [self._to_volume(volume) for volume in response.object['value']]
 
     def attach_volume(self, node, volume, ex_lun=None,
-                      ex_vhd_uri=None, ex_vhd_new=False, **ex_kwargs):
+                      ex_vhd_uri=None, ex_vhd_create=False, **ex_kwargs):
         """
         Attach a volume to node.
 
@@ -906,9 +906,9 @@ class AzureNodeDriver(NodeDriver):
             blob. (optional)
         :type ex_vhd_uri: ``str``
 
-        :param ex_vhd_new: Create a new VHD blob for unmanaged disk.
+        :param ex_vhd_create: Create a new VHD blob for unmanaged disk.
             (optional)
-        :type ex_vhd_new: ``bool``
+        :type ex_vhd_create: ``bool``
 
         :rtype: ``bool``
         """
@@ -930,7 +930,7 @@ class AzureNodeDriver(NodeDriver):
                 'name': volume.name,
                 'diskSizeGB': volume.size,
                 'lun': ex_lun,
-                'createOption': 'empty' if ex_vhd_new else 'attach',
+                'createOption': 'empty' if ex_vhd_create else 'attach',
                 'vhd': {'uri': ex_vhd_uri},
             }
         else:


[16/20] libcloud git commit: FAM-928 CR fixes

Posted by an...@apache.org.
FAM-928 CR fixes


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/2ade41d8
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/2ade41d8
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/2ade41d8

Branch: refs/heads/trunk
Commit: 2ade41d85e3666bf94892f9c72b6067aa86ddb02
Parents: 23ec91f
Author: mermoldy <s....@scalr.com>
Authored: Mon May 29 18:43:03 2017 +0300
Committer: Anthony Shaw <an...@apache.org>
Committed: Fri Aug 11 14:59:31 2017 +1000

----------------------------------------------------------------------
 libcloud/compute/drivers/azure_arm.py | 45 +++++-------------------------
 1 file changed, 7 insertions(+), 38 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/2ade41d8/libcloud/compute/drivers/azure_arm.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/azure_arm.py b/libcloud/compute/drivers/azure_arm.py
index 37c8815..d0de32f 100644
--- a/libcloud/compute/drivers/azure_arm.py
+++ b/libcloud/compute/drivers/azure_arm.py
@@ -887,7 +887,7 @@ class AzureNodeDriver(NodeDriver):
         return [self._to_volume(volume) for volume in response.object['value']]
 
     def attach_volume(self, node, volume, ex_lun=None,
-                      ex_vhd_uri=None, ex_vhd_resource_group=None, **ex_kwargs):
+                      ex_vhd_uri=None, ex_vhd_new=False, **ex_kwargs):
         """
         Attach a volume to node.
 
@@ -906,9 +906,9 @@ class AzureNodeDriver(NodeDriver):
             blob. (optional)
         :type ex_vhd_uri: ``str``
 
-        :param ex_vhd_resource_group: Storage account resource group name.
-            (required for ``ex_vhd_uri``)
-        :type ex_vhd_resource_group: ``str``
+        :param ex_vhd_new: Create a new VHD blob for unmanaged disk.
+            (optional)
+        :type ex_vhd_new: ``bool``
 
         :rtype: ``bool``
         """
@@ -926,20 +926,12 @@ class AzureNodeDriver(NodeDriver):
                 raise LibcloudError("No LUN available to attach new disk.")
 
         if ex_vhd_uri is not None:
-            if ex_vhd_resource_group is None:
-                raise AttributeError(
-                    "'ex_vhd_resource_group' of the VHD blob is not specified.")
-
-            # attach new or existing unmanaged disk
-            vhd_exists = self._ex_vhd_exists(
-                ex_vhd_resource_group,
-                ex_vhd_uri)
             new_disk = {
+                'name': volume.name,
+                'diskSizeGB': volume.size,
                 'lun': ex_lun,
-                'name': 'unmanaged-vol-{}'.format(str(uuid.uuid4())[0:8]),
-                'createOption': 'attach' if vhd_exists else 'empty',
+                'createOption': 'empty' if ex_vhd_new else 'attach',
                 'vhd': {'uri': ex_vhd_uri},
-                'diskSizeGB': volume.size
             }
         else:
             # attach existing managed disk
@@ -1913,29 +1905,6 @@ class AzureNodeDriver(NodeDriver):
         except ObjectDoesNotExistError:
             return True
 
-    def _ex_vhd_exists(self, resource_group, vhd_uri):
-        """
-        Check if VHD by given ``vhd_uri`` exists
-
-        :param resource_group: Storage account resource group name.
-        :type: ``str``
-
-        :param vhd_uri: Virtual hard disk's uri.
-        :type: ``str``
-
-        :rtype: ``bool``
-        """
-        try:
-            storage_account, blob_container, blob = _split_blob_uri(vhd_uri)
-            keys = self.ex_get_storage_account_keys(
-                resource_group, storage_account)
-            blob_driver = AzureBlobsStorageDriver(
-                storage_account, keys['key1'])
-            blob_driver.get_object(blob_container, blob)
-            return True
-        except ObjectDoesNotExistError:
-            return False
-
     def _ex_connection_class_kwargs(self):
         kwargs = super(AzureNodeDriver, self)._ex_connection_class_kwargs()
         kwargs['tenant_id'] = self.tenant_id


[08/20] libcloud git commit: FAM-690 WIP

Posted by an...@apache.org.
FAM-690 WIP


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/c2343ad2
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/c2343ad2
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/c2343ad2

Branch: refs/heads/trunk
Commit: c2343ad245d950f55df947bf28318b0ebc0cfe23
Parents: cbf1d5a
Author: mermoldy <s....@scalr.com>
Authored: Thu Mar 2 23:31:56 2017 +0200
Committer: Anthony Shaw <an...@apache.org>
Committed: Fri Aug 11 14:59:31 2017 +1000

----------------------------------------------------------------------
 libcloud/compute/drivers/azure_arm.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/c2343ad2/libcloud/compute/drivers/azure_arm.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/azure_arm.py b/libcloud/compute/drivers/azure_arm.py
index 632d9a7..d2f3c37 100644
--- a/libcloud/compute/drivers/azure_arm.py
+++ b/libcloud/compute/drivers/azure_arm.py
@@ -1118,7 +1118,7 @@ class AzureNodeDriver(NodeDriver):
                 u'/providers/Microsoft.Compute/disks/{volume_name}'
             ).format(
                 subscription_id=self.subscription_id,
-                resource_group=ex_resource_group.upper(),
+                resource_group=ex_resource_group,
                 volume_name=name
             )
         if volume_name is None and \
@@ -1186,7 +1186,7 @@ class AzureNodeDriver(NodeDriver):
                 u'/providers/Microsoft.Compute/snapshots/{snapshot_name}'
             ).format(
                 subscription_id=self.subscription_id,
-                resource_group=ex_resource_group.upper(),
+                resource_group=ex_resource_group,
                 snapshot_name=name
             )
 


[05/20] libcloud git commit: FAM-690 Disks support for azure resource manager driver

Posted by an...@apache.org.
FAM-690 Disks support for azure resource manager driver


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/4bd4af92
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/4bd4af92
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/4bd4af92

Branch: refs/heads/trunk
Commit: 4bd4af926e42f255296b0611dd7215a607633b91
Parents: 57fe733
Author: mermoldy <s....@scalr.com>
Authored: Mon Feb 20 17:32:15 2017 +0200
Committer: Anthony Shaw <an...@apache.org>
Committed: Fri Aug 11 14:59:31 2017 +1000

----------------------------------------------------------------------
 libcloud/compute/drivers/azure_arm.py | 377 ++++++++++++++++++++++++++---
 1 file changed, 344 insertions(+), 33 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/4bd4af92/libcloud/compute/drivers/azure_arm.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/azure_arm.py b/libcloud/compute/drivers/azure_arm.py
index 0340203..3f20b7e 100644
--- a/libcloud/compute/drivers/azure_arm.py
+++ b/libcloud/compute/drivers/azure_arm.py
@@ -27,9 +27,9 @@ import time
 from libcloud.common.azure_arm import AzureResourceManagementConnection
 from libcloud.compute.providers import Provider
 from libcloud.compute.base import Node, NodeDriver, NodeLocation, NodeSize
-from libcloud.compute.base import NodeImage, NodeAuthSSHKey
-from libcloud.compute.base import NodeAuthPassword
-from libcloud.compute.types import NodeState
+from libcloud.compute.base import NodeImage, StorageVolume
+from libcloud.compute.base import NodeAuthPassword, NodeAuthSSHKey
+from libcloud.compute.types import NodeState, StorageVolumeState
 from libcloud.common.types import LibcloudError
 from libcloud.storage.types import ObjectDoesNotExistError
 from libcloud.common.exceptions import BaseHTTPError
@@ -37,6 +37,9 @@ from libcloud.storage.drivers.azure_blobs import AzureBlobsStorageDriver
 from libcloud.utils.py3 import basestring
 
 
+RESOURCE_API_VERSION = '2016-04-30-preview'
+
+
 class AzureImage(NodeImage):
     """Represents a Marketplace node image that an Azure VM can boot from."""
 
@@ -164,6 +167,7 @@ class AzureNodeDriver(NodeDriver):
     type = Provider.AZURE_ARM
     features = {'create_node': ['ssh_key', 'password']}
 
+
     # The API doesn't provide state or country information, so fill it in.
     # Information from https://azure.microsoft.com/en-us/regions/
     _location_to_country = {
@@ -390,7 +394,8 @@ class AzureNodeDriver(NodeDriver):
                     ex_subnet=None,
                     ex_nic=None,
                     ex_tags={},
-                    ex_customdata=""):
+                    ex_customdata="",
+                    ex_use_managed_disks=False):
         """Create a new node instance. This instance will be started
         automatically.
 
@@ -411,7 +416,7 @@ class AzureNodeDriver(NodeDriver):
             >>> node = driver.create_node("test_node", auth=auth, ...)
 
         If you don't provide the ``auth`` argument libcloud will assign
-        a password::
+        a password:
 
             >>> driver = AzureNodeDriver(...)
             >>> node = driver.create_node("test_node", ...)
@@ -481,9 +486,15 @@ class AzureNodeDriver(NodeDriver):
             articles/virtual-machines-how-to-inject-custom-data/
         :type ex_customdata: ``str``
 
+        :param ex_use_managed_disks: Enable this feature to have Azure
+            automatically manage the availability of disks to provide data
+            redundancy and fault tolerance, without creating and managing
+            storage accounts on your own. Managed disks may not be available
+            in all regions.
+        :type ex_use_managed_disks: ``bool``
+
         :return: The newly created node.
         :rtype: :class:`.Node`
-
         """
 
         if location is None:
@@ -526,7 +537,7 @@ class AzureNodeDriver(NodeDriver):
                 n += 1
 
         if isinstance(image, AzureVhdImage):
-            storageProfile = {
+            storage_profile = {
                 "osDisk": {
                     "name": "virtualmachine-osDisk",
                     "osType": "linux",
@@ -541,7 +552,7 @@ class AzureNodeDriver(NodeDriver):
                 }
             }
         elif isinstance(image, AzureImage):
-            storageProfile = {
+            storage_profile = {
                 "imageReference": {
                     "publisher": image.publisher,
                     "offer": image.offer,
@@ -557,6 +568,12 @@ class AzureNodeDriver(NodeDriver):
                     "createOption": "FromImage"
                 }
             }
+            if ex_use_managed_disks:
+                storage_profile["osDisk"] = {
+                    "name": name,
+                    "createOption": "FromImage",
+                    "caching": "ReadWrite",
+                }
         else:
             raise LibcloudError(
                 "Unknown image type %s,"
@@ -573,7 +590,7 @@ class AzureNodeDriver(NodeDriver):
                 "hardwareProfile": {
                     "vmSize": size.id
                 },
-                "storageProfile": storageProfile,
+                "storageProfile": storage_profile,
                 "osProfile": {
                     "computerName": name
                 },
@@ -618,7 +635,7 @@ class AzureNodeDriver(NodeDriver):
                 "Must provide NodeAuthSSHKey or NodeAuthPassword in auth")
 
         r = self.connection.request(target,
-                                    params={"api-version": "2015-06-15"},
+                                    params={"api-version": RESOURCE_API_VERSION},
                                     data=data,
                                     method="PUT")
 
@@ -640,9 +657,10 @@ class AzureNodeDriver(NodeDriver):
 
         target = "%s/restart" % node.id
         try:
-            self.connection.request(target,
-                                    params={"api-version": "2015-06-15"},
-                                    method='POST')
+            self.connection.request(
+                target,
+                params={"api-version": RESOURCE_API_VERSION},
+                method='POST')
             return True
         except BaseHTTPError as h:
             if h.code == 202:
@@ -687,7 +705,7 @@ class AzureNodeDriver(NodeDriver):
                 time.sleep(10)
                 self.connection.request(
                     node.id,
-                    params={"api-version": "2015-06-15"})
+                    params={"api-version": RESOURCE_API_VERSION})
             except BaseHTTPError as h:
                 if h.code == 404:
                     break
@@ -702,11 +720,10 @@ class AzureNodeDriver(NodeDriver):
             for nic in interfaces:
                 while True:
                     try:
-                        self.connection.request(nic["id"],
-                                                params={
-                                                    "api-version":
-                                                    "2015-06-15"},
-                                                method='DELETE')
+                        self.connection.request(
+                            nic["id"],
+                            params={"api-version": RESOURCE_API_VERSION},
+                            method='DELETE')
                         break
                     except BaseHTTPError as h:
                         if h.code == 202:
@@ -718,15 +735,14 @@ class AzureNodeDriver(NodeDriver):
                             return False
 
         # Optionally clean up OS disk VHD.
-        vhd_uri = \
-            node.extra["properties"]["storageProfile"]["osDisk"]["vhd"]["uri"]
-        if ex_destroy_vhd:
+        vhd = node.extra["properties"]["storageProfile"]["osDisk"].get("vhd")
+        if ex_destroy_vhd and vhd is not None:
             while True:
                 try:
                     resourceGroup = node.id.split("/")[4]
                     self._ex_delete_old_vhd(
                         resourceGroup,
-                        vhd_uri)
+                        vhd["uri"])
                     break
                 except LibcloudError as e:
                     if "LeaseIdMissing" in str(e):
@@ -741,6 +757,297 @@ class AzureNodeDriver(NodeDriver):
 
         return True
 
+    def create_volume(self, size, name, location=None, snapshot=None,
+                      ex_resource_group=None, ex_tags=None):
+        """
+        Create a new volume.
+
+        :param size: Size of volume in gigabytes (required)
+        :type size: ``int``
+
+        :param name: Name of the volume to be created
+        :type name: ``str``
+
+        :param location: Which data center to create a volume in.
+        :type location: :class:`.NodeLocation`
+
+        :param snapshot: Snapshot from which to create the new
+            volume.  (optional)
+        :type snapshot: :class:`.VolumeSnapshot`
+
+        :param ex_resource_group: The name of resource group in which to
+            create the node.
+        :type ex_resource_group: ``str``
+
+        :param ex_tags: Optional tags to associate with this resource.
+        :type ex_tags: ``dict``
+
+        :return: The newly created volume.
+        :rtype: :class:`StorageVolume`
+        """
+
+        if location is None:
+            raise ValueError("Must provide `location` value")
+
+        if ex_resource_group is None:
+            raise ValueError("Must provide `ex_resource_group` value")
+
+        action = (
+            u'/subscriptions/{subscription_id}/resourceGroups/{resource_group}'
+            u'/providers/Microsoft.Compute/disks/{volume_name}'
+        ).format(
+            subscription_id=self.subscription_id,
+            resource_group=ex_resource_group,
+            volume_name=name,
+        )
+        tags = ex_tags if ex_tags is not None else {}
+        data = {
+            'location': location.id,
+            'tags': tags,
+            'properties': {
+                'creationData': {
+                    'createOption': 'Empty'
+                },
+                'diskSizeGB': size
+            }
+        }
+
+        response = self.connection.request(
+            action,
+            method='PUT',
+            params={
+                'api-version': RESOURCE_API_VERSION,
+            },
+            data=data
+        )
+
+        return self._to_volume(
+            response.object,
+            name=name,
+            ex_resource_group=ex_resource_group
+        )
+
+    def list_volumes(self, ex_resource_group=None):
+        """
+        Lists all the disks under a resource group or subscription.
+
+        :param ex_resource_group: The identifier of your subscription
+            where the managed disks are located.
+        :type ex_resource_group: ``str``
+
+        :rtype: list of :class:`StorageVolume`
+        """
+        if ex_resource_group:
+            action = u'/subscriptions/{subscription_id}/resourceGroups' \
+                     u'/{resource_group}/providers/Microsoft.Compute/disks'
+        else:
+            action = u'/subscriptions/{subscription_id}' \
+                     u'/providers/Microsoft.Compute/disks'
+
+        action = action.format(
+            subscription_id=self.subscription_id,
+            resource_group=ex_resource_group
+        )
+
+        response = self.connection.request(
+            action,
+            method='GET',
+            params={
+                'api-version': RESOURCE_API_VERSION
+            }
+        )
+        return [self._to_volume(volume) for volume in response.object['value']]
+
+    def attach_volume(self, node, volume, device=None, ex_lun=None):
+        """
+        Attach volume to node.
+
+        :param node: A node to attach volume.
+        :type node: :class:`Node`
+
+        :param volume: A volume to attach.
+        :type volume: :class:`StorageVolume`
+
+        :param device: A node device to attach volume(not supported by Azure).
+        :type device: ``str``
+
+        :param ex_lun: Specifies the logical unit number (LUN) location for
+            the data drive in the virtual machine. Each data disk must have
+            a unique LUN.
+        :type ex_lun: ``int``
+
+        :rtype: ``bool``
+        """
+        action = node.extra['id']
+        location = node.extra['location']
+        disks = node.extra['properties']['storageProfile']['dataDisks']
+
+        if ex_lun is None:
+            # find the smallest unused logical unit number
+            used_luns = [disk['lun'] for disk in disks]
+            for lun in range(0, 63):
+                if lun not in used_luns:
+                    ex_lun = lun
+                    break
+
+        disks.append({
+            'lun': ex_lun,
+            'name': volume.name,
+            'createOption': 'attach',
+            'managedDisk': {
+                'id': volume.id
+            }
+        })
+
+        response = self.connection.request(
+            action,
+            method='PUT',
+            params={
+                'api-version': RESOURCE_API_VERSION
+            },
+            data={
+                'properties': {
+                    'storageProfile': {
+                        'dataDisks': disks
+                    }
+                },
+                'location': location
+            }
+        )
+
+        disks = response.object['properties']['storageProfile']['dataDisks']
+        return volume.id in [disk['managedDisk']['id'] for disk in disks]
+
+    def detach_volume(self, volume, ex_node=None):
+        """
+        Detach a volume from a node.
+        """
+        if ex_node is None:
+            raise ValueError("Must provide `ex_node` value")
+
+        action = ex_node.extra['id']
+        location = ex_node.extra['location']
+        disks = ex_node.extra['properties']['storageProfile']['dataDisks']
+
+        # remove volume from `properties.storageProfile.dataDisks`
+        for index, disk in enumerate(disks):
+            if volume.id == disk['managedDisk']['id']:
+                del disks[index]
+
+        response = self.connection.request(
+            action,
+            method='PUT',
+            params={
+                'api-version': RESOURCE_API_VERSION
+            },
+            data={
+                'properties': {
+                    'storageProfile': {
+                        'dataDisks': disks
+                    }
+                },
+                'location': location
+            }
+        )
+
+        disks = response.object['properties']['storageProfile']['dataDisks']
+        return volume.id not in [disk['managedDisk']['id'] for disk in disks]
+
+    def destroy_volume(self, volume):
+        """
+        Delete a volume.
+        """
+        self.connection.request(
+            volume.id,
+            method='DELETE',
+            params={
+                'api-version': RESOURCE_API_VERSION
+            },
+        )
+        return True
+
+    def create_volume_snapshot(self, volume, name=None):
+        """
+        Create snapshot from volume.
+
+        :param volume: Instance of ``StorageVolume``
+        :type volume: :class`StorageVolume`
+
+        :param name: Name of snapshot (optional)
+        :type name: ``str``
+
+        :rtype: :class:`VolumeSnapshot`
+        """
+        super(AzureNodeDriver).create_volume_snapshot(volume, name=name)
+        # TODO
+
+    def _to_volume(self, volume_obj, name=None, ex_resource_group=None):
+        """
+        Parse the JSON element and return a StorageVolume object.
+
+        :param volume_obj: A volume object from an azure response.
+        :type volume_obj: ``dict``
+
+        :param name: An optional name for the volume. If not provided
+            then either tag with a key "name" will be used.
+        :type name: ``str``
+
+        :param ex_resource_group: An optional resource group for the volume.
+            If not provided then either tag with a key "resource_group"
+            will be used.
+        :type ex_resource_group: ``str``
+
+        :rtype: :class:`StorageVolume`
+        """
+        volume_id = volume_obj.get('id')
+        volume_name = volume_obj.get('name')
+        properties = volume_obj['properties']
+        size = int(properties['diskSizeGB'])
+        extra = {
+            'tags': volume_obj.get('tags', {}),
+            'location_id': volume_obj['location'],
+            'properties': properties,
+        }
+
+        provisioning_state = properties.get('provisioningState', '').lower()
+        disk_state = properties.get('diskState', '').lower()
+        if provisioning_state in ('creating', 'updating'):
+            state = StorageVolumeState.CREATING
+        elif provisioning_state == 'succeeded':
+            if disk_state in ('attached', 'reserved', 'activesas'):
+                state = StorageVolumeState.INUSE
+            elif disk_state == 'unattached':
+                state = StorageVolumeState.AVAILABLE
+            else:
+                state = StorageVolumeState.UNKNOWN
+        else:
+            state = StorageVolumeState.UNKNOWN
+
+        if volume_id is None and \
+                ex_resource_group is not None and \
+                name is not None:
+            volume_id = (
+                u'/subscriptions/{subscription_id}'
+                u'/resourceGroups/{resource_group}'
+                u'/providers/Microsoft.Compute/disks/{volume_name}'
+            ).format(
+                subscription_id=self.subscription_id,
+                resource_group=ex_resource_group.upper(),
+                volume_name=name
+            )
+        if volume_name is None and \
+                name is not None:
+            volume_name = name
+
+        return StorageVolume(
+            id=volume_id,
+            name=volume_name,
+            size=size,
+            driver=self,
+            state=state,
+            extra=extra
+        )
+
     def ex_get_ratecard(self, offer_durable_id, currency='USD',
                         locale='en-US', region='US'):
         """
@@ -992,24 +1299,28 @@ class AzureNodeDriver(NodeDriver):
         return [AzureSubnet(net["id"], net["name"], net["properties"])
                 for net in r.object["value"]]
 
-    def ex_list_nics(self, resource_group):
+    def ex_list_nics(self, ex_resource_group=None):
         """
         List available virtual network interface controllers
         in a resource group
 
-        :param resource_group: List NICS in a specific resource group
-        containing the NICs.
-        :type resource_group: ``str``
+        :param ex_resource_group: List NICS in a specific resource group
+            containing the NICs(optional).
+        :type ex_resource_group: ``str``
 
         :return: A list of NICs.
         :rtype: ``list`` of :class:`.AzureNic`
         """
-
-        action = "/subscriptions/%s/resourceGroups/%s" \
-                 "/providers/Microsoft.Network/networkInterfaces" % \
-                 (self.subscription_id, resource_group)
-        r = self.connection.request(action,
-                                    params={"api-version": "2015-06-15"})
+        if ex_resource_group is None:
+            action = "/subscriptions/%s/providers/Microsoft.Network" \
+                     "/networkInterfaces" % self.subscription_id
+        else:
+            action = "/subscriptions/%s/resourceGroups/%s/providers" \
+                     "/Microsoft.Network/networkInterfaces" % \
+                     (self.subscription_id, ex_resource_group)
+        r = self.connection.request(
+            action,
+            params={"api-version": RESOURCE_API_VERSION})
         return [self._to_nic(net) for net in r.object["value"]]
 
     def ex_get_nic(self, id):


[19/20] libcloud git commit: removed unused import Closes #1087

Posted by an...@apache.org.
removed unused import
Closes #1087


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/b3c411d1
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/b3c411d1
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/b3c411d1

Branch: refs/heads/trunk
Commit: b3c411d19eafddbd5ea480bcc1dfe932d16447e1
Parents: 39feeeb
Author: mermoldy <s....@scalr.com>
Authored: Mon Jun 5 14:01:17 2017 +0300
Committer: Anthony Shaw <an...@apache.org>
Committed: Fri Aug 11 14:59:36 2017 +1000

----------------------------------------------------------------------
 libcloud/compute/drivers/azure_arm.py | 1 -
 1 file changed, 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/b3c411d1/libcloud/compute/drivers/azure_arm.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/azure_arm.py b/libcloud/compute/drivers/azure_arm.py
index bd36731..eb770ad 100644
--- a/libcloud/compute/drivers/azure_arm.py
+++ b/libcloud/compute/drivers/azure_arm.py
@@ -21,7 +21,6 @@ http://azure.microsoft.com/en-us/services/virtual-machines/
 
 import base64
 import binascii
-import uuid
 import os
 import time
 


[18/20] libcloud git commit: FAM-895 added methods to directly request volume, node, snapshot objects from Azure

Posted by an...@apache.org.
FAM-895 added methods to directly request volume, node, snapshot objects from Azure


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/aba57d66
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/aba57d66
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/aba57d66

Branch: refs/heads/trunk
Commit: aba57d66f0c8d49549c52d95b4a3d560278d2db4
Parents: 4004c0d
Author: Hennadii Stas <ut...@gmail.com>
Authored: Thu May 18 12:50:54 2017 +0300
Committer: Anthony Shaw <an...@apache.org>
Committed: Fri Aug 11 14:59:31 2017 +1000

----------------------------------------------------------------------
 libcloud/compute/drivers/azure_arm.py | 42 ++++++++++++++++++++++++++++++
 libcloud/compute/drivers/ec2.py       |  4 +--
 2 files changed, 44 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/aba57d66/libcloud/compute/drivers/azure_arm.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/azure_arm.py b/libcloud/compute/drivers/azure_arm.py
index d5d56b7..da7596f 100644
--- a/libcloud/compute/drivers/azure_arm.py
+++ b/libcloud/compute/drivers/azure_arm.py
@@ -1533,6 +1533,48 @@ class AzureNodeDriver(NodeDriver):
         r = self.connection.request(id, params={"api-version": "2015-06-15"})
         return self._to_nic(r.object)
 
+    def ex_get_node(self, id):
+        """
+        Fetch information about a node.
+
+        :param id: The complete resource path to the node resource.
+        :type id: ``str``
+
+        :return: The Node object
+        :rtype: :class:`.Node`
+        """
+
+        r = self.connection.request(id, params={"api-version": "2015-06-15"})
+        return self._to_node(r.object)
+
+    def ex_get_volume(self, id):
+        """
+        Fetch information about a volume.
+
+        :param id: The complete resource path to the volume resource.
+        :type id: ``str``
+
+        :return: The StorageVolume object
+        :rtype: :class:`.StorageVolume`
+        """
+
+        r = self.connection.request(id, params={"api-version": "2015-06-15"})
+        return self._to_volume(r.object)
+
+    def ex_get_snapshot(self, id):
+        """
+        Fetch information about a snapshot.
+
+        :param id: The complete resource path to the snapshot resource.
+        :type id: ``str``
+
+        :return: The VolumeSnapshot object
+        :rtype: :class:`.VolumeSnapshot`
+        """
+
+        r = self.connection.request(id, params={"api-version": "2015-06-15"})
+        return self._to_snapshot(r.object)
+
     def ex_get_public_ip(self, id):
         """
         Fetch information about a public IP resource.

http://git-wip-us.apache.org/repos/asf/libcloud/blob/aba57d66/libcloud/compute/drivers/ec2.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/ec2.py b/libcloud/compute/drivers/ec2.py
index 26b789e..efb6275 100644
--- a/libcloud/compute/drivers/ec2.py
+++ b/libcloud/compute/drivers/ec2.py
@@ -6292,8 +6292,8 @@ class BaseEC2NodeDriver(NodeDriver):
         Modify volume parameters.
         A list of valid parameters can be found at https://goo.gl/N0rPEQ
 
-        :param      Volume: Volume instance
-        :type       Volume: :class:`Volume`
+        :param      volume: Volume instance
+        :type       volume: :class:`Volume`
 
         :param      parameters: Dictionary with updated volume parameters
         :type       parameters: ``dict``


[15/20] libcloud git commit: FAM-690 WIP

Posted by an...@apache.org.
FAM-690 WIP


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/774b0971
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/774b0971
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/774b0971

Branch: refs/heads/trunk
Commit: 774b097106ff022e48688dd554ca2d402cfd1367
Parents: c2343ad
Author: mermoldy <s....@scalr.com>
Authored: Mon Mar 6 20:18:07 2017 +0200
Committer: Anthony Shaw <an...@apache.org>
Committed: Fri Aug 11 14:59:31 2017 +1000

----------------------------------------------------------------------
 libcloud/compute/drivers/azure_arm.py | 32 ++++++++++++++++++++++--------
 1 file changed, 24 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/774b0971/libcloud/compute/drivers/azure_arm.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/azure_arm.py b/libcloud/compute/drivers/azure_arm.py
index d2f3c37..6a43d09 100644
--- a/libcloud/compute/drivers/azure_arm.py
+++ b/libcloud/compute/drivers/azure_arm.py
@@ -788,10 +788,10 @@ class AzureNodeDriver(NodeDriver):
         :rtype: :class:`StorageVolume`
         """
         if location is None:
-            raise ValueError("Must provide `location` value")
+            raise ValueError("Must provide `location` value.")
 
         if ex_resource_group is None:
-            raise ValueError("Must provide `ex_resource_group` value")
+            raise ValueError("Must provide `ex_resource_group` value.")
 
         action = (
             u'/subscriptions/{subscription_id}/resourceGroups/{resource_group}'
@@ -926,17 +926,28 @@ class AzureNodeDriver(NodeDriver):
         Detach a managed volume from a node.
         """
         if ex_node is None:
-            raise ValueError("Must provide `ex_node` value")
+            raise ValueError("Must provide `ex_node` value.")
 
         action = ex_node.extra['id']
         location = ex_node.extra['location']
         disks = ex_node.extra['properties']['storageProfile']['dataDisks']
 
         # remove volume from `properties.storageProfile.dataDisks`
+        disk_index = None
         for index, disk in enumerate(disks):
             if 'managedDisk' in disk:
                 if volume.id == disk['managedDisk'].get('id'):
-                    del disks[index]
+                    disk_index = index
+            elif 'name' in disk:
+                if volume.name == disk['name']:
+                    disk_index = index
+        if disk_index is None:
+            raise LibcloudError((
+                "A disk with id {} does not found among managed disks "
+                "attached to an instance ({})."
+            ).format(volume.id, ex_node.id))
+        else:
+            del disks[disk_index]
 
         self.connection.request(
             action,
@@ -1656,14 +1667,16 @@ class AzureNodeDriver(NodeDriver):
             resource = resource.id
         r = self.connection.request(
             resource,
-            params={"api-version": "2015-06-15"})
+            params={"api-version": RESOURCE_API_VERSION})
         if replace:
             r.object["tags"] = tags
         else:
             r.object["tags"].update(tags)
-        r = self.connection.request(resource, data={"tags": r.object["tags"]},
-                                    params={"api-version": "2015-06-15"},
-                                    method="PATCH")
+        self.connection.request(
+            resource,
+            data={"tags": r.object["tags"]},
+            params={"api-version": RESOURCE_API_VERSION},
+            method="PATCH")
 
     def ex_start_node(self, node):
         """
@@ -1870,6 +1883,9 @@ class AzureNodeDriver(NodeDriver):
                 elif status["code"].startswith("ProvisioningState/failed"):
                     state = NodeState.ERROR
                     break
+                elif status["code"] == "ProvisioningState/updating":
+                    state = NodeState.RECONFIGURING
+                    break
                 elif status["code"] == "ProvisioningState/succeeded":
                     pass
 


[03/20] libcloud git commit: FAM-902 Fixed api version

Posted by an...@apache.org.
FAM-902 Fixed api version


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/439e4dc8
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/439e4dc8
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/439e4dc8

Branch: refs/heads/trunk
Commit: 439e4dc878de430ca41a258e27abf121c5721e44
Parents: aba57d6
Author: mermoldy <s....@scalr.com>
Authored: Mon May 22 20:22:01 2017 +0300
Committer: Anthony Shaw <an...@apache.org>
Committed: Fri Aug 11 14:59:31 2017 +1000

----------------------------------------------------------------------
 libcloud/compute/drivers/azure_arm.py | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/439e4dc8/libcloud/compute/drivers/azure_arm.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/azure_arm.py b/libcloud/compute/drivers/azure_arm.py
index da7596f..eed44d0 100644
--- a/libcloud/compute/drivers/azure_arm.py
+++ b/libcloud/compute/drivers/azure_arm.py
@@ -1544,7 +1544,8 @@ class AzureNodeDriver(NodeDriver):
         :rtype: :class:`.Node`
         """
 
-        r = self.connection.request(id, params={"api-version": "2015-06-15"})
+        r = self.connection.request(
+            id, params={"api-version": RESOURCE_API_VERSION})
         return self._to_node(r.object)
 
     def ex_get_volume(self, id):
@@ -1558,7 +1559,8 @@ class AzureNodeDriver(NodeDriver):
         :rtype: :class:`.StorageVolume`
         """
 
-        r = self.connection.request(id, params={"api-version": "2015-06-15"})
+        r = self.connection.request(
+            id, params={"api-version": RESOURCE_API_VERSION})
         return self._to_volume(r.object)
 
     def ex_get_snapshot(self, id):
@@ -1572,7 +1574,8 @@ class AzureNodeDriver(NodeDriver):
         :rtype: :class:`.VolumeSnapshot`
         """
 
-        r = self.connection.request(id, params={"api-version": "2015-06-15"})
+        r = self.connection.request(
+            id, params={"api-version": RESOURCE_API_VERSION})
         return self._to_snapshot(r.object)
 
     def ex_get_public_ip(self, id):


[06/20] libcloud git commit: FAM-690 Snapshots support for azure resource manager driver

Posted by an...@apache.org.
FAM-690 Snapshots support for azure resource manager driver


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/6078d854
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/6078d854
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/6078d854

Branch: refs/heads/trunk
Commit: 6078d854685c8e2114bdef840425828505e19ba8
Parents: 4bd4af9
Author: mermoldy <s....@scalr.com>
Authored: Mon Feb 27 18:55:30 2017 +0200
Committer: Anthony Shaw <an...@apache.org>
Committed: Fri Aug 11 14:59:31 2017 +1000

----------------------------------------------------------------------
 libcloud/compute/drivers/azure_arm.py | 229 +++++++++++++++++++++++++----
 1 file changed, 199 insertions(+), 30 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/6078d854/libcloud/compute/drivers/azure_arm.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/azure_arm.py b/libcloud/compute/drivers/azure_arm.py
index 3f20b7e..57117f3 100644
--- a/libcloud/compute/drivers/azure_arm.py
+++ b/libcloud/compute/drivers/azure_arm.py
@@ -27,14 +27,16 @@ import time
 from libcloud.common.azure_arm import AzureResourceManagementConnection
 from libcloud.compute.providers import Provider
 from libcloud.compute.base import Node, NodeDriver, NodeLocation, NodeSize
-from libcloud.compute.base import NodeImage, StorageVolume
+from libcloud.compute.base import NodeImage, StorageVolume, VolumeSnapshot
 from libcloud.compute.base import NodeAuthPassword, NodeAuthSSHKey
-from libcloud.compute.types import NodeState, StorageVolumeState
+from libcloud.compute.types import (NodeState, StorageVolumeState,
+                                    VolumeSnapshotState)
 from libcloud.common.types import LibcloudError
 from libcloud.storage.types import ObjectDoesNotExistError
 from libcloud.common.exceptions import BaseHTTPError
 from libcloud.storage.drivers.azure_blobs import AzureBlobsStorageDriver
 from libcloud.utils.py3 import basestring
+from libcloud.utils.iso8601 import parse_date
 
 
 RESOURCE_API_VERSION = '2016-04-30-preview'
@@ -769,14 +771,14 @@ class AzureNodeDriver(NodeDriver):
         :type name: ``str``
 
         :param location: Which data center to create a volume in.
-        :type location: :class:`.NodeLocation`
+        :type location: :class:`NodeLocation`
 
         :param snapshot: Snapshot from which to create the new
             volume.  (optional)
-        :type snapshot: :class:`.VolumeSnapshot`
+        :type snapshot: :class:`VolumeSnapshot`
 
         :param ex_resource_group: The name of resource group in which to
-            create the node.
+            create the volume.
         :type ex_resource_group: ``str``
 
         :param ex_tags: Optional tags to associate with this resource.
@@ -785,7 +787,6 @@ class AzureNodeDriver(NodeDriver):
         :return: The newly created volume.
         :rtype: :class:`StorageVolume`
         """
-
         if location is None:
             raise ValueError("Must provide `location` value")
 
@@ -811,6 +812,13 @@ class AzureNodeDriver(NodeDriver):
                 'diskSizeGB': size
             }
         }
+        if snapshot is not None:
+            data['properties']['creationData'] = {
+                'createOption': 'Copy',
+                'sourceUri': {
+                    'id': snapshot.id
+                }
+            }
 
         response = self.connection.request(
             action,
@@ -892,7 +900,6 @@ class AzureNodeDriver(NodeDriver):
 
         disks.append({
             'lun': ex_lun,
-            'name': volume.name,
             'createOption': 'attach',
             'managedDisk': {
                 'id': volume.id
@@ -957,29 +964,117 @@ class AzureNodeDriver(NodeDriver):
         """
         Delete a volume.
         """
-        self.connection.request(
-            volume.id,
-            method='DELETE',
-            params={
-                'api-version': RESOURCE_API_VERSION
-            },
-        )
+        self.ex_delete_resource(volume)
         return True
 
-    def create_volume_snapshot(self, volume, name=None):
+    def create_volume_snapshot(self, volume, name=None, location=None,
+                               ex_resource_group=None, ex_tags=None):
         """
         Create snapshot from volume.
 
-        :param volume: Instance of ``StorageVolume``
+        :param volume: Instance of ``StorageVolume``.
         :type volume: :class`StorageVolume`
 
-        :param name: Name of snapshot (optional)
+        :param name: Name of snapshot (optional).
         :type name: ``str``
 
+        :param location: Which data center to create a volume in.
+        :type location: :class:`NodeLocation`
+
+        :param ex_resource_group: The name of resource group in which to
+            create the snapshot.
+        :type ex_resource_group: ``str``
+
+        :param ex_tags: Optional tags to associate with this resource.
+        :type ex_tags: ``dict``
+
         :rtype: :class:`VolumeSnapshot`
         """
-        super(AzureNodeDriver).create_volume_snapshot(volume, name=name)
-        # TODO
+        if name is None:
+            raise ValueError("Must provide `name` value")
+        if location is None:
+            raise ValueError("Must provide `location` value")
+        if ex_resource_group is None:
+            raise ValueError("Must provide `ex_resource_group` value")
+
+        snapshot_id = (
+            u'/subscriptions/{subscription_id}'
+            u'/resourceGroups/{resource_group}'
+            u'/providers/Microsoft.Compute'
+            u'/snapshots/{snapshot_name}'
+        ).format(
+            subscription_id=self.subscription_id,
+            resource_group=ex_resource_group,
+            snapshot_name=name,
+        )
+        tags = ex_tags if ex_tags is not None else {}
+
+        data = {
+            'location': location.id,
+            'tags': tags,
+            'properties': {
+                'creationData': {
+                    'createOption': 'Copy',
+                    'sourceUri': volume.id
+                },
+            }
+        }
+        response = self.connection.request(
+            snapshot_id,
+            method='PUT',
+            data=data,
+            params={
+                'api-version': RESOURCE_API_VERSION
+            },
+        )
+
+        return self._to_snapshot(
+            response.object,
+            name=name,
+            ex_resource_group=ex_resource_group
+        )
+
+    def list_volume_snapshots(self, volume):
+        return [snapshot for snapshot in self.list_snapshots()
+                if snapshot.extra['source_id'] == volume.id]
+
+    def list_snapshots(self, ex_resource_group=None):
+        """
+        Lists all the snapshots under a resource group or subscription.
+
+        :param ex_resource_group: The identifier of your subscription
+            where the managed snapshots are located (optional).
+        :type ex_resource_group: ``str``
+
+        :rtype: list of :class:`VolumeSnapshot`
+        """
+        if ex_resource_group:
+            action = u'/subscriptions/{subscription_id}/resourceGroups' \
+                     u'/{resource_group}/providers/Microsoft.Compute/snapshots'
+        else:
+            action = u'/subscriptions/{subscription_id}' \
+                     u'/providers/Microsoft.Compute/snapshots'
+
+        action = action.format(
+            subscription_id=self.subscription_id,
+            resource_group=ex_resource_group
+        )
+
+        response = self.connection.request(
+            action,
+            method='GET',
+            params={
+                'api-version': RESOURCE_API_VERSION
+            }
+        )
+        return [self._to_snapshot(snap) for snap in response.object['value']]
+
+    def destroy_volume_snapshot(self, snapshot):
+        """
+        Delete a snapshot.
+        """
+        self.ex_delete_resource(snapshot)
+        return True
 
     def _to_volume(self, volume_obj, name=None, ex_resource_group=None):
         """
@@ -989,25 +1084,21 @@ class AzureNodeDriver(NodeDriver):
         :type volume_obj: ``dict``
 
         :param name: An optional name for the volume. If not provided
-            then either tag with a key "name" will be used.
+            then either tag with a key "name" will be used. (optional)
         :type name: ``str``
 
         :param ex_resource_group: An optional resource group for the volume.
             If not provided then either tag with a key "resource_group"
-            will be used.
+            will be used. (optional)
         :type ex_resource_group: ``str``
 
         :rtype: :class:`StorageVolume`
         """
         volume_id = volume_obj.get('id')
         volume_name = volume_obj.get('name')
-        properties = volume_obj['properties']
+        extra = dict(volume_obj)
+        properties = extra['properties']
         size = int(properties['diskSizeGB'])
-        extra = {
-            'tags': volume_obj.get('tags', {}),
-            'location_id': volume_obj['location'],
-            'properties': properties,
-        }
 
         provisioning_state = properties.get('provisioningState', '').lower()
         disk_state = properties.get('diskState', '').lower()
@@ -1023,9 +1114,9 @@ class AzureNodeDriver(NodeDriver):
         else:
             state = StorageVolumeState.UNKNOWN
 
-        if volume_id is None and \
-                ex_resource_group is not None and \
-                name is not None:
+        if volume_id is None \
+                and ex_resource_group is not None \
+                and name is not None:
             volume_id = (
                 u'/subscriptions/{subscription_id}'
                 u'/resourceGroups/{resource_group}'
@@ -1048,6 +1139,84 @@ class AzureNodeDriver(NodeDriver):
             extra=extra
         )
 
+    def _to_snapshot(self, snapshot_obj, name=None,  ex_resource_group=None):
+        """
+        Parse the JSON element and return a VolumeSnapshot object.
+
+        :param snapshot_obj: A snapshot object from an azure response.
+        :type snapshot_obj: ``dict``
+
+        :param name: An optional name for the volume.
+        :type name: ``str``
+
+        :param ex_resource_group: An optional resource group for the volume.
+            If not provided then either tag with a key "resource_group"
+            will be used.
+        :type ex_resource_group: ``str``
+
+        :rtype: :class:`VolumeSnapshot`
+        """
+        snapshot_id = snapshot_obj.get('id')
+        name = snapshot_obj.get('name', name)
+        properties = snapshot_obj['properties']
+        size = properties.get('diskSizeGB')
+        if size is not None:
+            size = int(size)
+        extra = dict(snapshot_obj)
+        extra['source_id'] = properties['creationData']['sourceUri']
+        if '/providers/Microsoft.Compute/disks/' in extra['source_id']:
+            extra['volume_id'] = extra['source_id']
+
+        provisioning_state = properties.get('provisioningState', '').lower()
+        if provisioning_state in ('creating', 'updating'):
+            state = VolumeSnapshotState.CREATING
+        elif provisioning_state == 'succeeded':
+            state = VolumeSnapshotState.AVAILABLE
+        elif provisioning_state == 'failed':
+            state = VolumeSnapshotState.ERROR
+        else:
+            state = VolumeSnapshotState.UNKNOWN
+
+        try:
+            created_at = parse_date(snapshot_obj['properties']['timeCreated'])
+        except ValueError:
+            created_at = None
+
+        if snapshot_id is None \
+                and ex_resource_group is not None \
+                and name is not None:
+            snapshot_id = (
+                u'/subscriptions/{subscription_id}'
+                u'/resourceGroups/{resource_group}'
+                u'/providers/Microsoft.Compute/snapshots/{snapshot_name}'
+            ).format(
+                subscription_id=self.subscription_id,
+                resource_group=ex_resource_group.upper(),
+                snapshot_name=name
+            )
+
+        return VolumeSnapshot(
+            snapshot_id,
+            name=name,
+            size=size,
+            driver=self,
+            state=state,
+            extra=extra,
+            created=created_at
+        )
+
+    def ex_delete_resource(self, resource):
+        """
+        Delete a resource.
+        """
+        self.connection.request(
+            resource.id,
+            method='DELETE',
+            params={
+                'api-version': RESOURCE_API_VERSION
+            },
+        )
+
     def ex_get_ratecard(self, offer_durable_id, currency='USD',
                         locale='en-US', region='US'):
         """


[20/20] libcloud git commit: changes for #1087

Posted by an...@apache.org.
changes for #1087


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/c7e81a5f
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/c7e81a5f
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/c7e81a5f

Branch: refs/heads/trunk
Commit: c7e81a5f618586016a3b89994269312328370154
Parents: b3c411d
Author: Anthony Shaw <an...@apache.org>
Authored: Fri Aug 11 15:00:33 2017 +1000
Committer: Anthony Shaw <an...@apache.org>
Committed: Fri Aug 11 15:00:33 2017 +1000

----------------------------------------------------------------------
 CHANGES.rst | 4 ++++
 1 file changed, 4 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/c7e81a5f/CHANGES.rst
----------------------------------------------------------------------
diff --git a/CHANGES.rst b/CHANGES.rst
index fa3ae62..14c28fa 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -18,6 +18,10 @@ Compute
   [GITHUB-1066]
   (Francois Regnoult)
 
+- [ARM] Add Storage support, volumes, snapshots
+  [GITHUB-1087]
+  (Sergey Babak)
+
 Container
 ~~~~~~~~~
 


[11/20] libcloud git commit: FAM-690 Added tests

Posted by an...@apache.org.
FAM-690 Added tests


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/4ab938a1
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/4ab938a1
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/4ab938a1

Branch: refs/heads/trunk
Commit: 4ab938a19c24c964306e097e373fdb1a69136d3b
Parents: 5352e71
Author: mermoldy <s....@scalr.com>
Authored: Thu Mar 9 20:33:26 2017 +0200
Committer: Anthony Shaw <an...@apache.org>
Committed: Fri Aug 11 14:59:31 2017 +1000

----------------------------------------------------------------------
 libcloud/compute/drivers/azure_arm.py           |  33 +-
 ...99999999999_providers_Microsoft_Compute.json |   2 +-
 ...99999_providers_Microsoft_Compute_disks.json |  65 ++++
 ...9_providers_Microsoft_Compute_snapshots.json |  75 ++++
 ...iders_Microsoft_Compute_virtualMachines.json |  52 +++
 ...ers_Microsoft_Compute_disks_test_disk_1.json |  22 ++
 ...Microsoft_Compute_snapshots_test_snap_1.json |  20 ++
 ...oft_Compute_virtualMachines_test_node_1.json |  48 +++
 ...irtualMachines_test_node_1_InstanceView.json |  27 ++
 ...twork_networkInterfaces_test_node_1_nic.json |  38 +++
 ...11111_providers_Microsoft_Compute_disks.json |  22 ++
 ...1_providers_Microsoft_Compute_snapshots.json |  38 +++
 libcloud/test/compute/test_azure_arm.py         | 342 ++++++++++++++++++-
 13 files changed, 752 insertions(+), 32 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/4ab938a1/libcloud/compute/drivers/azure_arm.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/azure_arm.py b/libcloud/compute/drivers/azure_arm.py
index 3326a74..b85eb77 100644
--- a/libcloud/compute/drivers/azure_arm.py
+++ b/libcloud/compute/drivers/azure_arm.py
@@ -492,7 +492,7 @@ class AzureNodeDriver(NodeDriver):
             automatically manage the availability of disks to provide data
             redundancy and fault tolerance, without creating and managing
             storage accounts on your own. Managed disks may not be available
-            in all regions.
+            in all regions (default False).
         :type ex_use_managed_disks: ``bool``
 
         :param ex_storage_account_type: The Storage Account type,
@@ -772,21 +772,20 @@ class AzureNodeDriver(NodeDriver):
         """
         Create a new volume.
 
-        :param size: Size of volume in gigabytes (required)
+        :param size: Size of volume in gigabytes.
         :type size: ``int``
 
-        :param name: Name of the volume to be created
+        :param name: Name of the volume to be created.
         :type name: ``str``
 
-        :param location: Which data center to create a volume in.
+        :param location: Which data center to create a volume in. (required)
         :type location: :class:`NodeLocation`
 
-        :param snapshot: Snapshot from which to create the new
-            volume.  (optional)
+        :param snapshot: Snapshot from which to create the new volume.
         :type snapshot: :class:`VolumeSnapshot`
 
         :param ex_resource_group: The name of resource group in which to
-            create the volume.
+            create the volume. (required)
         :type ex_resource_group: ``str``
 
         :param ex_tags: Optional tags to associate with this resource.
@@ -872,7 +871,7 @@ class AzureNodeDriver(NodeDriver):
         )
         return [self._to_volume(volume) for volume in response.object['value']]
 
-    def attach_volume(self, node, volume, device=None, ex_lun=None):
+    def attach_volume(self, node, volume, ex_lun=None, **ex_kwargs):
         """
         Attach a managed volume to node.
 
@@ -882,9 +881,6 @@ class AzureNodeDriver(NodeDriver):
         :param volume: A volume to attach.
         :type volume: :class:`StorageVolume`
 
-        :param device: A node device to attach volume(not supported by Azure).
-        :type device: ``str``
-
         :param ex_lun: Specifies the logical unit number (LUN) location for
             the data drive in the virtual machine. Each data disk must have
             a unique LUN.
@@ -989,14 +985,14 @@ class AzureNodeDriver(NodeDriver):
         :param volume: Instance of ``StorageVolume``.
         :type volume: :class`StorageVolume`
 
-        :param name: Name of snapshot (optional).
+        :param name: Name of snapshot. (required)
         :type name: ``str``
 
-        :param location: Which data center to create a volume in.
+        :param location: Which data center to create a volume in. (required)
         :type location: :class:`NodeLocation`
 
         :param ex_resource_group: The name of resource group in which to
-            create the snapshot.
+            create the snapshot. (required)
         :type ex_resource_group: ``str``
 
         :param ex_tags: Optional tags to associate with this resource.
@@ -1097,13 +1093,10 @@ class AzureNodeDriver(NodeDriver):
         :param volume_obj: A volume object from an azure response.
         :type volume_obj: ``dict``
 
-        :param name: An optional name for the volume. If not provided
-            then either tag with a key "name" will be used. (optional)
+        :param name: An optional name for the volume.
         :type name: ``str``
 
         :param ex_resource_group: An optional resource group for the volume.
-            If not provided then either tag with a key "resource_group"
-            will be used. (optional)
         :type ex_resource_group: ``str``
 
         :rtype: :class:`StorageVolume`
@@ -1156,7 +1149,7 @@ class AzureNodeDriver(NodeDriver):
             extra=extra
         )
 
-    def _to_snapshot(self, snapshot_obj, name=None,  ex_resource_group=None):
+    def _to_snapshot(self, snapshot_obj, name=None, ex_resource_group=None):
         """
         Parse the JSON element and return a VolumeSnapshot object.
 
@@ -1167,8 +1160,6 @@ class AzureNodeDriver(NodeDriver):
         :type name: ``str``
 
         :param ex_resource_group: An optional resource group for the volume.
-            If not provided then either tag with a key "resource_group"
-            will be used.
         :type ex_resource_group: ``str``
 
         :rtype: :class:`VolumeSnapshot`

http://git-wip-us.apache.org/repos/asf/libcloud/blob/4ab938a1/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_providers_Microsoft_Compute.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_providers_Microsoft_Compute.json b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_providers_Microsoft_Compute.json
index 7c4b5cd..f0bbae5 100644
--- a/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_providers_Microsoft_Compute.json
+++ b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_providers_Microsoft_Compute.json
@@ -197,4 +197,4 @@
     }
   ],
   "registrationState": "Registered"
-}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/4ab938a1/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_providers_Microsoft_Compute_disks.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_providers_Microsoft_Compute_disks.json b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_providers_Microsoft_Compute_disks.json
new file mode 100644
index 0000000..849a5a8
--- /dev/null
+++ b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_providers_Microsoft_Compute_disks.json
@@ -0,0 +1,65 @@
+{
+  "value": [
+    {
+      "properties": {
+        "accountType": "Standard_LRS",
+        "osType": "Linux",
+        "creationData": {
+          "createOption": "FromImage",
+          "imageReference": {
+            "id": "/Subscriptions/99999999-9999-9999-9999-999999999999/Providers/Microsoft.Compute/Locations/eastus/Publishers/OpenLogic/ArtifactTypes/VMImage/Offers/CentOS/Skus/7.3/Versions/latest"
+          }
+        },
+        "diskSizeGB": 31,
+        "timeCreated": "2017-03-09T10:12:37.0256203+00:00",
+        "ownerId": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/REVIZOR/providers/Microsoft.Compute/virtualMachines/test-vm-1",
+        "provisioningState": "Succeeded",
+        "diskState": "Attached"
+      },
+      "type": "Microsoft.Compute/disks",
+      "location": "eastus",
+      "tags": {},
+      "id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/000000/providers/Microsoft.Compute/disks/test-disk-1",
+      "name": "test-disk-1"
+    },
+    {
+      "properties": {
+        "accountType": "Standard_LRS",
+        "osType": "Linux",
+        "creationData": {
+          "createOption": "FromImage",
+          "imageReference": {
+            "id": "/Subscriptions/99999999-9999-9999-9999-999999999999/Providers/Microsoft.Compute/Locations/eastus/Publishers/OpenLogic/ArtifactTypes/VMImage/Offers/CentOS/Skus/7.3/Versions/latest"
+          }
+        },
+        "diskSizeGB": 31,
+        "timeCreated": "2017-03-09T11:40:37.092158+00:00",
+        "provisioningState": "Updating",
+        "diskState": "Unattached"
+      },
+      "type": "Microsoft.Compute/disks",
+      "location": "eastus",
+      "tags": {},
+      "id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/000000/providers/Microsoft.Compute/disks/test-disk-2",
+      "name": "test-disk-2"
+    },
+    {
+      "properties": {
+        "accountType": "Standard_LRS",
+        "osType": "Linux",
+        "creationData": {
+          "createOption": "Empty"
+        },
+        "diskSizeGB": 10,
+        "timeCreated": "2017-03-09T10:08:42.6418313+00:00",
+        "provisioningState": "Succeeded",
+        "diskState": "Unattached"
+      },
+      "type": "Microsoft.Compute/disks",
+      "location": "eastus",
+      "tags": {},
+      "id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/111111/providers/Microsoft.Compute/disks/test-disk-3",
+      "name": "test-disk-3"
+    }
+  ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/4ab938a1/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_providers_Microsoft_Compute_snapshots.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_providers_Microsoft_Compute_snapshots.json b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_providers_Microsoft_Compute_snapshots.json
new file mode 100644
index 0000000..8fe42b2
--- /dev/null
+++ b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_providers_Microsoft_Compute_snapshots.json
@@ -0,0 +1,75 @@
+{
+  "value": [
+    {
+      "properties": {
+        "accountType": "Standard_LRS",
+        "creationData": {
+          "createOption": "Copy",
+          "sourceUri": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/000000/providers/Microsoft.Compute/disks/test-disk-1"
+        },
+        "diskSizeGB": 1,
+        "timeCreated": "2017-03-09T14:28:27.8655868+00:00",
+        "provisioningState": "Creating",
+        "diskState": "Unattached"
+      },
+      "type": "Microsoft.Compute/snapshots",
+      "location": "eastus",
+      "tags": {
+        "test_snap": "test"
+      },
+      "id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/000000/providers/Microsoft.Compute/snapshots/test-snap-1",
+      "name": "test-snap-1"
+    },
+    {
+      "properties": {
+        "accountType": "Standard_LRS",
+        "creationData": {
+          "createOption": "Copy",
+          "sourceUri": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/000000/providers/Microsoft.Compute/disks/test-disk-2"
+        },
+        "diskSizeGB": 2,
+        "timeCreated": "2017-02-02T17:52:40.2213321+00:00",
+        "provisioningState": "Updating",
+        "diskState": "Unattached"
+      },
+      "type": "Microsoft.Compute/snapshots",
+      "location": "eastus",
+      "id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/000000/providers/Microsoft.Compute/snapshots/test-snap-2",
+      "name": "test-snap-2"
+    },
+    {
+      "properties": {
+        "accountType": "Standard_LRS",
+        "creationData": {
+          "createOption": "Copy",
+          "sourceUri": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/111111/providers/Microsoft.Compute/disks/test-disk-3"
+        },
+        "diskSizeGB": 2,
+        "timeCreated": "2017-02-02T17:52:44.4557501+00:00",
+        "provisioningState": "Failed",
+        "diskState": "Unattached"
+      },
+      "type": "Microsoft.Compute/snapshots",
+      "location": "eastus",
+      "id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/111111/providers/Microsoft.Compute/snapshots/test-snap-3",
+      "name": "test-snap-3"
+    },
+    {
+      "properties": {
+        "accountType": "Standard_LRS",
+        "creationData": {
+          "createOption": "Copy",
+          "sourceUri": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/111111/providers/Microsoft.Compute/disks/test-disk-4"
+        },
+        "diskSizeGB": 2,
+        "timeCreated": "2017-02-02T17:52:50.0027361+00:00",
+        "provisioningState": "Failed",
+        "diskState": "Unattached"
+      },
+      "type": "Microsoft.Compute/snapshots",
+      "location": "eastus",
+      "id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/111111/providers/Microsoft.Compute/snapshots/test-snap-4",
+      "name": "test-snap-4"
+    }
+  ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/4ab938a1/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_providers_Microsoft_Compute_virtualMachines.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_providers_Microsoft_Compute_virtualMachines.json b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_providers_Microsoft_Compute_virtualMachines.json
new file mode 100644
index 0000000..8973cf9
--- /dev/null
+++ b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_providers_Microsoft_Compute_virtualMachines.json
@@ -0,0 +1,52 @@
+{
+  "value": [
+    {
+      "properties": {
+        "vmId": "CCEEBF63-E92B-4A50-9949-6E44BFC61D3F",
+        "hardwareProfile": {
+          "vmSize": "Standard_A1"
+        },
+        "storageProfile": {
+          "imageReference": {
+            "publisher": "OpenLogic",
+            "offer": "CentOS",
+            "sku": "7.3",
+            "version": "latest"
+          },
+          "osDisk": {
+            "osType": "Linux",
+            "name": "test-node-disk-1",
+            "createOption": "FromImage",
+            "caching": "ReadWrite",
+            "managedDisk": {
+              "storageAccountType": "Standard_LRS",
+              "id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/000000/providers/Microsoft.Compute/disks/test-node-disk-1"
+            }
+          },
+          "dataDisks": []
+        },
+        "osProfile": {
+          "computerName": "test-node-1",
+          "adminUsername": "user",
+          "linuxConfiguration": {
+            "disablePasswordAuthentication": false
+          },
+          "secrets": []
+        },
+        "networkProfile": {
+          "networkInterfaces": [
+            {
+              "id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/000000/providers/Microsoft.Network/networkInterfaces/test-node-1-nic"
+            }
+          ]
+        },
+        "provisioningState": "Running"
+      },
+      "type": "Microsoft.Compute/virtualMachines",
+      "location": "eastus",
+      "tags": {},
+      "id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/000000/providers/Microsoft.Compute/virtualMachines/test-node-1",
+      "name": "test-node-1"
+    }
+  ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/4ab938a1/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_resourceGroups_000000_providers_Microsoft_Compute_disks_test_disk_1.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_resourceGroups_000000_providers_Microsoft_Compute_disks_test_disk_1.json b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_resourceGroups_000000_providers_Microsoft_Compute_disks_test_disk_1.json
new file mode 100644
index 0000000..584b72e
--- /dev/null
+++ b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_resourceGroups_000000_providers_Microsoft_Compute_disks_test_disk_1.json
@@ -0,0 +1,22 @@
+{
+  "properties": {
+    "accountType": "Standard_LRS",
+    "osType": "Linux",
+    "creationData": {
+      "createOption": "FromImage",
+      "imageReference": {
+        "id": "/Subscriptions/99999999-9999-9999-9999-999999999999/Providers/Microsoft.Compute/Locations/eastus/Publishers/OpenLogic/ArtifactTypes/VMImage/Offers/CentOS/Skus/7.3/Versions/latest"
+      }
+    },
+    "diskSizeGB": 31,
+    "timeCreated": "2017-03-09T10:12:37.0256203+00:00",
+    "ownerId": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/REVIZOR/providers/Microsoft.Compute/virtualMachines/test-vm-1",
+    "provisioningState": "Succeeded",
+    "diskState": "Attached"
+  },
+  "type": "Microsoft.Compute/disks",
+  "location": "eastus",
+  "tags": {},
+  "id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/000000/providers/Microsoft.Compute/disks/test-disk-1",
+  "name": "test-disk-1"
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/4ab938a1/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_resourceGroups_000000_providers_Microsoft_Compute_snapshots_test_snap_1.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_resourceGroups_000000_providers_Microsoft_Compute_snapshots_test_snap_1.json b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_resourceGroups_000000_providers_Microsoft_Compute_snapshots_test_snap_1.json
new file mode 100644
index 0000000..f83c70d
--- /dev/null
+++ b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_resourceGroups_000000_providers_Microsoft_Compute_snapshots_test_snap_1.json
@@ -0,0 +1,20 @@
+{
+  "properties": {
+    "accountType": "Standard_LRS",
+    "creationData": {
+      "createOption": "Copy",
+      "sourceUri": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/000000/providers/Microsoft.Compute/disks/test-disk-1"
+    },
+    "diskSizeGB": 1,
+    "timeCreated": "2017-03-09T14:28:27.8655868+00:00",
+    "provisioningState": "Creating",
+    "diskState": "Unattached"
+  },
+  "type": "Microsoft.Compute/snapshots",
+  "location": "eastus",
+  "tags": {
+    "test_snap": "test"
+  },
+  "id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/000000/providers/Microsoft.Compute/snapshots/test-snap-1",
+  "name": "test-snap-1"
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/4ab938a1/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_resourceGroups_000000_providers_Microsoft_Compute_virtualMachines_test_node_1.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_resourceGroups_000000_providers_Microsoft_Compute_virtualMachines_test_node_1.json b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_resourceGroups_000000_providers_Microsoft_Compute_virtualMachines_test_node_1.json
new file mode 100644
index 0000000..c45d32f
--- /dev/null
+++ b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_resourceGroups_000000_providers_Microsoft_Compute_virtualMachines_test_node_1.json
@@ -0,0 +1,48 @@
+{
+  "properties": {
+    "vmId": "e717ae77-db36-4225-b12a-68506fe5fc8f",
+    "hardwareProfile": {
+      "vmSize": "Standard_A1"
+    },
+    "storageProfile": {
+      "imageReference": {
+        "publisher": "OpenLogic",
+        "offer": "CentOS",
+        "sku": "7.3",
+        "version": "latest"
+      },
+      "osDisk": {
+        "osType": "Linux",
+        "name": "test-node-disk-1",
+        "createOption": "FromImage",
+        "caching": "ReadWrite",
+        "managedDisk": {
+          "storageAccountType": "Standard_LRS",
+          "id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/000000/providers/Microsoft.Compute/disks/test-node-disk-1"
+        }
+      },
+      "dataDisks": []
+    },
+    "osProfile": {
+      "computerName": "test-node-1",
+      "adminUsername": "user",
+      "linuxConfiguration": {
+        "disablePasswordAuthentication": false
+      },
+      "secrets": []
+    },
+    "networkProfile": {
+      "networkInterfaces": [
+        {
+          "id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/000000/providers/Microsoft.Network/networkInterfaces/test-node-1-nic"
+        }
+      ]
+    },
+    "provisioningState": "Running"
+  },
+  "type": "Microsoft.Compute/virtualMachines",
+  "location": "eastus",
+  "tags": {},
+  "id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/000000/providers/Microsoft.Compute/virtualMachines/test-node-1",
+  "name": "test-node-1"
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/4ab938a1/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_resourceGroups_000000_providers_Microsoft_Compute_virtualMachines_test_node_1_InstanceView.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_resourceGroups_000000_providers_Microsoft_Compute_virtualMachines_test_node_1_InstanceView.json b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_resourceGroups_000000_providers_Microsoft_Compute_virtualMachines_test_node_1_InstanceView.json
new file mode 100644
index 0000000..0ac000f
--- /dev/null
+++ b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_resourceGroups_000000_providers_Microsoft_Compute_virtualMachines_test_node_1_InstanceView.json
@@ -0,0 +1,27 @@
+{
+  "vmAgent": {
+    "vmAgentVersion": "2.2.5",
+    "statuses": [
+      {
+        "code": "ProvisioningState/succeeded",
+        "level": "Info",
+        "displayStatus": "Ready",
+        "message": "Guest Agent is running",
+        "time": "2017-03-09T15:11:03+00:00"
+      }
+    ],
+    "extensionHandlers": []
+  },
+  "statuses": [
+    {
+      "code": "ProvisioningState/updating",
+      "level": "Info",
+      "displayStatus": "Updating"
+    },
+    {
+      "code": "PowerState/running",
+      "level": "Info",
+      "displayStatus": "VM running"
+    }
+  ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/4ab938a1/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_resourceGroups_000000_providers_Microsoft_Network_networkInterfaces_test_node_1_nic.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_resourceGroups_000000_providers_Microsoft_Network_networkInterfaces_test_node_1_nic.json b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_resourceGroups_000000_providers_Microsoft_Network_networkInterfaces_test_node_1_nic.json
new file mode 100644
index 0000000..c9cfb05
--- /dev/null
+++ b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_resourceGroups_000000_providers_Microsoft_Network_networkInterfaces_test_node_1_nic.json
@@ -0,0 +1,38 @@
+{
+  "name": "test-node-1-nic",
+  "id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/000000/providers/Microsoft.Network/networkInterfaces/test-node-1-nic",
+  "etag": "W/\"5E19562E-8E84-493D-A29E-A84F5AC21D76\"",
+  "location": "eastus",
+  "tags": {},
+  "properties": {
+    "provisioningState": "Succeeded",
+    "resourceGuid": "AD512C3D-9A7B-4012-8C5D-227A9EA5E6F4",
+    "ipConfigurations": [
+      {
+        "name": "myip1",
+        "id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/000000/providers/Microsoft.Network/networkInterfaces/test-node-1-nic/ipConfigurations/myip1",
+        "etag": "W/\"5E19562E-8E84-493D-A29E-A84F5AC21D76\"",
+        "properties": {
+          "provisioningState": "Succeeded",
+          "privateIPAddress": "10.0.0.1",
+          "privateIPAllocationMethod": "Dynamic",
+          "subnet": {
+            "id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/000000/providers/Microsoft.Network/virtualNetworks/000000/subnets/000000"
+          },
+          "primary": true
+        }
+      }
+    ],
+    "dnsSettings": {
+      "dnsServers": [],
+      "appliedDnsServers": []
+    },
+    "macAddress": "11-11-11-11-11-11",
+    "enableIPForwarding": false,
+    "primary": true,
+    "virtualMachine": {
+      "id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/000000/providers/Microsoft.Compute/virtualMachines/test-node-1"
+    }
+  },
+  "type": "Microsoft.Network/networkInterfaces"
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/4ab938a1/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_resourceGroups_111111_providers_Microsoft_Compute_disks.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_resourceGroups_111111_providers_Microsoft_Compute_disks.json b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_resourceGroups_111111_providers_Microsoft_Compute_disks.json
new file mode 100644
index 0000000..bd2de1f
--- /dev/null
+++ b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_resourceGroups_111111_providers_Microsoft_Compute_disks.json
@@ -0,0 +1,22 @@
+{
+  "value": [
+    {
+      "properties": {
+        "accountType": "Standard_LRS",
+        "osType": "Linux",
+        "creationData": {
+          "createOption": "Empty"
+        },
+        "diskSizeGB": 10,
+        "timeCreated": "2017-03-09T10:08:42.6418313+00:00",
+        "provisioningState": "Succeeded",
+        "diskState": "Unattached"
+      },
+      "type": "Microsoft.Compute/disks",
+      "location": "eastus",
+      "tags": {},
+      "id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/111111/providers/Microsoft.Compute/disks/test-disk-3",
+      "name": "test-disk-3"
+    }
+  ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/4ab938a1/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_resourceGroups_111111_providers_Microsoft_Compute_snapshots.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_resourceGroups_111111_providers_Microsoft_Compute_snapshots.json b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_resourceGroups_111111_providers_Microsoft_Compute_snapshots.json
new file mode 100644
index 0000000..b6add16
--- /dev/null
+++ b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_9999_9999_9999_999999999999_resourceGroups_111111_providers_Microsoft_Compute_snapshots.json
@@ -0,0 +1,38 @@
+{
+  "value": [
+    {
+      "properties": {
+        "accountType": "Standard_LRS",
+        "creationData": {
+          "createOption": "Copy",
+          "sourceUri": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/111111/providers/Microsoft.Compute/disks/test-disk-3"
+        },
+        "diskSizeGB": 2,
+        "timeCreated": "2017-02-02T17:52:44.4557501+00:00",
+        "provisioningState": "Failed",
+        "diskState": "Unattached"
+      },
+      "type": "Microsoft.Compute/snapshots",
+      "location": "eastus",
+      "id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/111111/providers/Microsoft.Compute/snapshots/test-snap-3",
+      "name": "test-snap-3"
+    },
+    {
+      "properties": {
+        "accountType": "Standard_LRS",
+        "creationData": {
+          "createOption": "Copy",
+          "sourceUri": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/111111/providers/Microsoft.Compute/disks/test-disk-4"
+        },
+        "diskSizeGB": 2,
+        "timeCreated": "2017-02-02T17:52:50.0027361+00:00",
+        "provisioningState": "Failed",
+        "diskState": "Unattached"
+      },
+      "type": "Microsoft.Compute/snapshots",
+      "location": "eastus",
+      "id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/111111/providers/Microsoft.Compute/snapshots/test-snap-4",
+      "name": "test-snap-4"
+    }
+  ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/4ab938a1/libcloud/test/compute/test_azure_arm.py
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/test_azure_arm.py b/libcloud/test/compute/test_azure_arm.py
index c0317c6..38fd484 100644
--- a/libcloud/test/compute/test_azure_arm.py
+++ b/libcloud/test/compute/test_azure_arm.py
@@ -12,13 +12,22 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.import libcloud
+import json
+import sys
+import functools
+from datetime import datetime
 
-from libcloud.test import LibcloudTestCase
-from libcloud.test import MockHttp
+from libcloud.compute.base import (NodeLocation, NodeSize, VolumeSnapshot,
+                                   StorageVolume)
+from libcloud.compute.drivers.azure_arm import AzureImage, NodeAuthPassword
+from libcloud.compute.providers import get_driver
+from libcloud.compute.types import (NodeState, Provider, StorageVolumeState,
+                                    VolumeSnapshotState)
+from libcloud.test import LibcloudTestCase, MockHttp
+from libcloud.test import unittest
 from libcloud.test.file_fixtures import ComputeFileFixtures
+from libcloud.utils.iso8601 import UTC
 from libcloud.utils.py3 import httplib
-from libcloud.compute.types import Provider
-from libcloud.compute.providers import get_driver
 
 
 class AzureNodeDriverTests(LibcloudTestCase):
@@ -50,7 +59,8 @@ class AzureNodeDriverTests(LibcloudTestCase):
                           "Japan West"])
 
     def test_sizes_returned_successfully(self):
-        sizes = self.driver.list_sizes(location=self.driver.list_locations()[0])
+        location = self.driver.list_locations()[0]
+        sizes = self.driver.list_sizes(location=location)
         self.assertEqual([l.name for l in sizes],
                          ["Standard_A0",
                           "Standard_A1",
@@ -65,14 +75,326 @@ class AzureNodeDriverTests(LibcloudTestCase):
                               'OfferTerms',
                               'Meters']))
 
+    def test_create_node(self):
+        location = NodeLocation('any_location', '', '', self.driver)
+        size = NodeSize('any_size', '', 0, 0, 0, 0, driver=self.driver)
+        image = AzureImage('1', '1', 'ubuntu', 'pub', location.id, self.driver)
+        auth = NodeAuthPassword('any_password')
+
+        node = self.driver.create_node(
+            'test-node-1',
+            size,
+            image,
+            auth,
+            location=location,
+            ex_resource_group='000000',
+            ex_storage_account='000000',
+            ex_user_name='any_user',
+            ex_network='000000',
+            ex_subnet='000000',
+            ex_use_managed_disks=True
+        )
+        hardware_profile = node.extra['properties']['hardwareProfile']
+        os_profile = node.extra['properties']['osProfile']
+        storage_profile = node.extra['properties']['storageProfile']
+
+        self.assertEqual(node.name, 'test-node-1')
+        self.assertEqual(node.state, NodeState.UPDATING)
+        self.assertEqual(node.private_ips, ['10.0.0.1'])
+        self.assertEqual(node.public_ips, [])
+        self.assertEqual(node.extra['location'], location.id)
+        self.assertEqual(hardware_profile['vmSize'], size.id)
+        self.assertEqual(os_profile['adminUsername'], 'any_user')
+        self.assertEqual(os_profile['adminPassword'], 'any_password')
+        self.assertTrue('managedDisk' in storage_profile['osDisk'])
+        self.assertTrue(storage_profile['imageReference'], {
+            'publisher': image.publisher,
+            'offer': image.offer,
+            'sku': image.sku,
+            'version': image.version
+        })
+
+    def test_list_nodes(self):
+        nodes = self.driver.list_nodes()
+
+        self.assertEqual(len(nodes), 1)
+
+        self.assertEqual(nodes[0].name, 'test-node-1')
+        self.assertEqual(nodes[0].state, NodeState.UPDATING)
+        self.assertEqual(nodes[0].private_ips, ['10.0.0.1'])
+        self.assertEqual(nodes[0].public_ips, [])
+
+    def test_create_volume(self):
+        location = self.driver.list_locations()[-1]
+        volume = self.driver.create_volume(
+            2, 'test-disk-1', location,
+            ex_resource_group='000000',
+            ex_tags={'description': 'MyVolume'}
+        )
+
+        self.assertEqual(volume.size, 2)
+        self.assertEqual(volume.name, 'test-disk-1')
+        self.assertEqual(volume.extra['name'], 'test-disk-1')
+        self.assertEqual(volume.extra['tags'], {'description': 'MyVolume'})
+        self.assertEqual(volume.extra['location'], location.id)
+        self.assertEqual(
+            volume.extra['properties']['creationData']['createOption'],
+            'Empty')
+        self.assertEqual(
+            volume.extra['properties']['provisioningState'],
+            'Succeeded')
+        self.assertEqual(
+            volume.extra['properties']['diskState'],
+            'Attached')
+        self.assertEqual(volume.state, StorageVolumeState.INUSE)
+
+    def test_create_volume__with_snapshot(self):
+        location = self.driver.list_locations()[0]
+        snap_id = (
+            '/subscriptions/99999999-9999-9999-9999-999999999999'
+            '/resourceGroups/000000/providers/Microsoft.Compute'
+            '/snapshots/test-snap-1'
+        )
+        snapshot = VolumeSnapshot(id=snap_id, size=2, driver=self.driver)
+
+        volume = self.driver.create_volume(
+            2, 'test-disk-1', location,
+            snapshot=snapshot,
+            ex_resource_group='000000',
+            ex_tags={'description': 'MyVolume'}
+        )
+
+        self.assertEqual(
+            volume.extra['properties']['creationData']['createOption'],
+            'Copy')
+        self.assertEqual(
+            volume.extra['properties']['creationData']['sourceUri'],
+            snap_id)
+
+    def test_create_volume__required_kw(self):
+        location = self.driver.list_locations()[0]
+        fn = functools.partial(self.driver.create_volume, 2, 'test-disk-1')
+
+        self.assertRaises(ValueError, fn)
+        self.assertRaises(ValueError, fn, location=location)
+        self.assertRaises(ValueError, fn, ex_resource_group='000000')
+
+        ret_value = fn(ex_resource_group='000000', location=location)
+        self.assertTrue(isinstance(ret_value, StorageVolume))
+
+    def test_list_volumes(self):
+        volumes = self.driver.list_volumes()
+
+        self.assertEqual(len(volumes), 3)
+
+        self.assertEqual(volumes[0].name, 'test-disk-1')
+        self.assertEqual(volumes[0].size, 31)
+        self.assertEqual(
+            volumes[0].extra['properties']['provisioningState'],
+            'Succeeded')
+        self.assertEqual(
+            volumes[0].extra['properties']['diskState'],
+            'Attached')
+        self.assertEqual(volumes[0].state, StorageVolumeState.INUSE)
+
+        self.assertEqual(volumes[1].name, 'test-disk-2')
+        self.assertEqual(volumes[1].size, 31)
+        self.assertEqual(
+            volumes[1].extra['properties']['provisioningState'],
+            'Updating')
+        self.assertEqual(
+            volumes[1].extra['properties']['diskState'],
+            'Unattached')
+        self.assertEqual(volumes[1].state, StorageVolumeState.UPDATING)
+
+        self.assertEqual(volumes[2].name, 'test-disk-3')
+        self.assertEqual(volumes[2].size, 10)
+        self.assertEqual(
+            volumes[2].extra['properties']['provisioningState'],
+            'Succeeded')
+        self.assertEqual(
+            volumes[2].extra['properties']['diskState'],
+            'Unattached')
+        self.assertEqual(StorageVolumeState.AVAILABLE, volumes[2].state)
+
+    def test_list_volumes__with_resource_group(self):
+        volumes = self.driver.list_volumes(ex_resource_group='111111')
+
+        self.assertEqual(len(volumes), 1)
+
+        self.assertEqual(volumes[0].name, 'test-disk-3')
+        self.assertEqual(volumes[0].size, 10)
+        self.assertEqual(
+            volumes[0].extra['properties']['provisioningState'],
+            'Succeeded')
+        self.assertEqual(
+            volumes[0].extra['properties']['diskState'],
+            'Unattached')
+        self.assertEqual(volumes[0].state, StorageVolumeState.AVAILABLE)
+
+    def test_attach_volume(self):
+        volumes = self.driver.list_volumes()
+        node = self.driver.list_nodes()[0]
+
+        self.driver.attach_volume(node, volumes[0], ex_lun=0)
+        self.driver.attach_volume(node, volumes[1], ex_lun=15)
+        self.driver.attach_volume(node, volumes[2])
+
+        data_disks = node.extra['properties']['storageProfile']['dataDisks']
+        luns = [disk['lun'] for disk in data_disks]
+        self.assertTrue(len(data_disks), len(volumes))
+        self.assertTrue(set(luns), set([0, 1, 15]))
+
+    def test_detach_volume(self):
+        volumes = self.driver.list_volumes()
+        node = self.driver.list_nodes()[0]
+
+        for volume in volumes:
+            self.driver.attach_volume(node, volume)
+
+        data_disks = node.extra['properties']['storageProfile']['dataDisks']
+        self.assertEqual(len(data_disks), len(volumes))
+
+        for volume in volumes:
+            self.driver.detach_volume(volume, ex_node=node)
+
+        data_disks = node.extra['properties']['storageProfile']['dataDisks']
+        self.assertEqual(len(data_disks), 0)
+
+    def test_destroy_volume(self):
+        volume = self.driver.list_volumes()[0]
+        ret_value = self.driver.destroy_volume(volume)
+        self.assertTrue(ret_value)
+
+    def test_create_volume_snapshot(self):
+        location = self.driver.list_locations()[-1]
+        volume = self.driver.list_volumes()[0]
+
+        snap = self.driver.create_volume_snapshot(
+            volume, 'test-snap-1',
+            location=location,
+            ex_resource_group='000000'
+        )
+        self.assertEqual(snap.name, 'test-snap-1')
+        self.assertEqual(snap.extra['name'], 'test-snap-1')
+        self.assertEqual(snap.size, 1)
+        self.assertEqual(snap.extra['source_id'], volume.id)
+        self.assertEqual(snap.state, VolumeSnapshotState.CREATING)
+        self.assertEqual(snap.extra['location'], location.id)
+        self.assertEqual(
+            snap.extra['properties']['provisioningState'],
+            'Creating')
+        self.assertEqual(
+            snap.extra['properties']['diskState'],
+            'Unattached')
+        # 2017-03-09T14:28:27.8655868+00:00"
+        self.assertEqual(
+            datetime(2017, 3, 9, 14, 28, 27, 865586, tzinfo=UTC),
+            snap.created)
+
+    def test_create_volume_snapshot__required_kw(self):
+        location = self.driver.list_locations()[0]
+        volume = self.driver.list_volumes()[0]
+
+        fn = functools.partial(self.driver.create_volume_snapshot, volume)
+
+        self.assertRaises(ValueError, fn)
+        self.assertRaises(ValueError, fn, name='test-snap-1')
+        self.assertRaises(ValueError, fn, location=location)
+        self.assertRaises(ValueError, fn, ex_resource_group='000000')
+
+        ret_value = fn(
+            name='test-snap-1',
+            ex_resource_group='000000',
+            location=location
+        )
+        self.assertTrue(isinstance(ret_value, VolumeSnapshot))
+
+    def test_list_snapshots(self):
+        snaps = self.driver.list_snapshots()
+        self.assertEqual(len(snaps), 4)
+
+        self.assertEqual(snaps[0].name, 'test-snap-1')
+        self.assertEqual(snaps[0].extra['name'], 'test-snap-1')
+        self.assertEqual(snaps[0].state, VolumeSnapshotState.CREATING)
+        self.assertEqual(
+            snaps[0].extra['source_id'],
+            '/subscriptions/99999999-9999-9999-9999-999999999999'
+            '/resourceGroups/000000/providers/Microsoft.Compute'
+            '/disks/test-disk-1')
+        self.assertEqual(snaps[0].size, 1)
+        self.assertEqual(snaps[0].extra['tags']['test_snap'], 'test')
+        self.assertTrue(isinstance(snaps[3].created, datetime))
+
+        self.assertEqual(snaps[3].name, 'test-snap-4')
+        self.assertEqual(snaps[3].extra['name'], 'test-snap-4')
+        self.assertEqual(snaps[3].state, VolumeSnapshotState.ERROR)
+        self.assertEqual(
+            snaps[3].extra['source_id'],
+            '/subscriptions/99999999-9999-9999-9999-999999999999'
+            '/resourceGroups/111111/providers/Microsoft.Compute'
+            '/disks/test-disk-4')
+        self.assertEqual(snaps[3].size, 2)
+        self.assertTrue(isinstance(snaps[3].created, datetime))
+
+    def test_list_snapshots_in_resource_group(self):
+
+        snaps = self.driver.list_snapshots(ex_resource_group='111111')
+        self.assertEqual(len(snaps), 2)
+
+        self.assertEqual(snaps[0].name, 'test-snap-3')
+        self.assertEqual(snaps[0].extra['name'], 'test-snap-3')
+        self.assertEqual(snaps[0].state, VolumeSnapshotState.ERROR)
+        self.assertEqual(
+            snaps[0].extra['source_id'],
+            '/subscriptions/99999999-9999-9999-9999-999999999999'
+            '/resourceGroups/111111/providers/Microsoft.Compute'
+            '/disks/test-disk-3')
+        self.assertEqual(snaps[0].size, 2)
+        self.assertTrue(isinstance(snaps[0].created, datetime))
+
+    def test_list_volume_snapshots(self):
+        volume = self.driver.list_volumes()[0]
+        self.assertTrue(volume.name == 'test-disk-1')
+
+        snapshots = self.driver.list_volume_snapshots(volume)
+        self.assertEqual(len(snapshots), 1)
+        self.assertEqual(snapshots[0].name, 'test-snap-1')
+        self.assertEqual(volume.id, snapshots[0].extra['source_id'])
+
+    def test_destroy_volume_snapshot(self):
+        snapshot = self.driver.list_snapshots()[0]
+        res_value = snapshot.destroy()
+        self.assertTrue(res_value)
+
 
 class AzureMockHttp(MockHttp):
     fixtures = ComputeFileFixtures('azure_arm')
 
+    def _update(self, fixture, body):
+        for key, value in body.items():
+            if isinstance(value, dict):
+                fixture[key] = self._update(fixture.get(key, {}), value)
+            else:
+                fixture[key] = body[key]
+        return fixture
+
     def __getattr__(self, n):
-        def m(method, url, body, headers):
-            return (httplib.OK,
-                    self.fixtures.load(n + ".json"),
-                    headers,
+        def fn(method, url, body, headers):
+            fixture = self.fixtures.load(n + ".json")
+
+            if method in ('POST', 'PUT'):
+                try:
+                    body = json.loads(body)
+                    fixture_tmp = json.loads(fixture)
+                    fixture_tmp = self._update(fixture_tmp, body)
+                    fixture = json.dumps(fixture_tmp)
+                except ValueError:
+                    pass
+            return (httplib.OK, fixture, headers,
                     httplib.responses[httplib.OK])
-        return m
+        return fn
+
+
+if __name__ == '__main__':
+    sys.exit(unittest.main())


[10/20] libcloud git commit: FAM-690 Disk size fix

Posted by an...@apache.org.
FAM-690 Disk size fix


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/c0c6e561
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/c0c6e561
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/c0c6e561

Branch: refs/heads/trunk
Commit: c0c6e56190f4286a1ea85f96e4d8c9449bc78a3c
Parents: 4ab938a
Author: mermoldy <s....@scalr.com>
Authored: Fri Mar 10 15:41:50 2017 +0200
Committer: Anthony Shaw <an...@apache.org>
Committed: Fri Aug 11 14:59:31 2017 +1000

----------------------------------------------------------------------
 libcloud/compute/drivers/azure_arm.py | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/c0c6e561/libcloud/compute/drivers/azure_arm.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/azure_arm.py b/libcloud/compute/drivers/azure_arm.py
index b85eb77..cc5f370 100644
--- a/libcloud/compute/drivers/azure_arm.py
+++ b/libcloud/compute/drivers/azure_arm.py
@@ -1105,7 +1105,9 @@ class AzureNodeDriver(NodeDriver):
         volume_name = volume_obj.get('name')
         extra = dict(volume_obj)
         properties = extra['properties']
-        size = int(properties['diskSizeGB'])
+        size = properties.get('diskSizeGB')
+        if size is not None:
+            size = int(size)
 
         provisioning_state = properties.get('provisioningState', '').lower()
         disk_state = properties.get('diskState', '').lower()


[14/20] libcloud git commit: FAM-902 Added attaching blob based disk

Posted by an...@apache.org.
FAM-902 Added attaching blob based disk


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/4004c0dd
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/4004c0dd
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/4004c0dd

Branch: refs/heads/trunk
Commit: 4004c0dd7bb047af5f96a8b8398a711bb0e5660d
Parents: f4fa364
Author: mermoldy <s....@scalr.com>
Authored: Fri May 12 17:18:03 2017 +0300
Committer: Anthony Shaw <an...@apache.org>
Committed: Fri Aug 11 14:59:31 2017 +1000

----------------------------------------------------------------------
 libcloud/compute/drivers/azure_arm.py | 47 ++++++++++++++++++++++++------
 1 file changed, 38 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/4004c0dd/libcloud/compute/drivers/azure_arm.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/azure_arm.py b/libcloud/compute/drivers/azure_arm.py
index a24368c..d5d56b7 100644
--- a/libcloud/compute/drivers/azure_arm.py
+++ b/libcloud/compute/drivers/azure_arm.py
@@ -21,6 +21,7 @@ http://azure.microsoft.com/en-us/services/virtual-machines/
 
 import base64
 import binascii
+import uuid
 import os
 import time
 
@@ -778,7 +779,7 @@ class AzureNodeDriver(NodeDriver):
                       ex_resource_group=None, ex_account_type=None,
                       ex_tags=None):
         """
-        Create a new volume.
+        Create a new managed volume.
 
         :param size: Size of volume in gigabytes.
         :type size: ``int``
@@ -798,7 +799,7 @@ class AzureNodeDriver(NodeDriver):
 
         :param ex_account_type: The Storage Account type,
             ``Standard_LRS``(HDD disks) or ``Premium_LRS``(SSD disks).
-        :type ex_account_type: str
+        :type ex_account_type: ``str``
 
         :param ex_tags: Optional tags to associate with this resource.
         :type ex_tags: ``dict``
@@ -885,7 +886,7 @@ class AzureNodeDriver(NodeDriver):
         )
         return [self._to_volume(volume) for volume in response.object['value']]
 
-    def attach_volume(self, node, volume, ex_lun=None, **ex_kwargs):
+    def attach_volume(self, node, volume, ex_lun=None, ex_vhd_uri=None, **ex_kwargs):
         """
         Attach a managed volume to node.
 
@@ -900,6 +901,10 @@ class AzureNodeDriver(NodeDriver):
             a unique LUN.
         :type ex_lun: ``int``
 
+        :param ex_vhd_uri: Attach old-style un-managed disk from VHD
+            blob. (optional)
+        :type ex_vhd_uri: ``str``
+
         :rtype: ``bool``
         """
         action = node.extra['id']
@@ -915,14 +920,26 @@ class AzureNodeDriver(NodeDriver):
             else:
                 raise LibcloudError("No LUN available to attach new disk.")
 
-        disks.append({
-            'lun': ex_lun,
-            'createOption': 'attach',
-            'managedDisk': {
-                'id': volume.id
+        if ex_vhd_uri is not None:
+            # attach new or existing unmanaged disk
+            resource_group = node.id.split('/')[4]
+            is_vhd_exists = self._ex_is_vhd_exists(resource_group, ex_vhd_uri)
+            new_disk = {
+                'lun': ex_lun,
+                'name': 'unmanaged-vol-{}'.format(str(uuid.uuid4())[0:8]),
+                'createOption': 'attach' if is_vhd_exists else 'empty',
+                'vhd': {'uri': ex_vhd_uri},
+                'diskSizeGB': volume.size
+            }
+        else:
+            # attach existing managed disk
+            new_disk = {
+                'lun': ex_lun,
+                'createOption': 'attach',
+                'managedDisk': {'id': volume.id}
             }
-        })
 
+        disks.append(new_disk)
         self.connection.request(
             action,
             method='PUT',
@@ -1843,6 +1860,18 @@ class AzureNodeDriver(NodeDriver):
         except ObjectDoesNotExistError:
             return True
 
+    def _ex_is_vhd_exists(self, resource_group, uri):
+        try:
+            storage_account, blob_container, blob = _split_blob_uri(uri)
+            keys = self.ex_get_storage_account_keys(
+                resource_group, storage_account)
+            blob_driver = AzureBlobsStorageDriver(
+                storage_account, keys['key1'])
+            blob_driver.get_object(blob_container, blob)
+            return True
+        except ObjectDoesNotExistError:
+            return False
+
     def _ex_connection_class_kwargs(self):
         kwargs = super(AzureNodeDriver, self)._ex_connection_class_kwargs()
         kwargs['tenant_id'] = self.tenant_id


[13/20] libcloud git commit: FAM-690 added disk accound type

Posted by an...@apache.org.
FAM-690 added disk accound type


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/f4fa3640
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/f4fa3640
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/f4fa3640

Branch: refs/heads/trunk
Commit: f4fa3640e061793887dd3341b356a6e108078345
Parents: a3fd017
Author: mermoldy <s....@scalr.com>
Authored: Fri Mar 17 12:28:14 2017 +0200
Committer: Anthony Shaw <an...@apache.org>
Committed: Fri Aug 11 14:59:31 2017 +1000

----------------------------------------------------------------------
 libcloud/compute/drivers/azure_arm.py | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/f4fa3640/libcloud/compute/drivers/azure_arm.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/azure_arm.py b/libcloud/compute/drivers/azure_arm.py
index 07fc28e..a24368c 100644
--- a/libcloud/compute/drivers/azure_arm.py
+++ b/libcloud/compute/drivers/azure_arm.py
@@ -775,7 +775,8 @@ class AzureNodeDriver(NodeDriver):
         return True
 
     def create_volume(self, size, name, location=None, snapshot=None,
-                      ex_resource_group=None, ex_tags=None):
+                      ex_resource_group=None, ex_account_type=None,
+                      ex_tags=None):
         """
         Create a new volume.
 
@@ -795,6 +796,10 @@ class AzureNodeDriver(NodeDriver):
             create the volume. (required)
         :type ex_resource_group: ``str``
 
+        :param ex_account_type: The Storage Account type,
+            ``Standard_LRS``(HDD disks) or ``Premium_LRS``(SSD disks).
+        :type ex_account_type: str
+
         :param ex_tags: Optional tags to associate with this resource.
         :type ex_tags: ``dict``
 
@@ -831,6 +836,8 @@ class AzureNodeDriver(NodeDriver):
                 'diskSizeGB': size
             }
         }
+        if ex_account_type is not None:
+            data['properties']['accountType'] = ex_account_type
 
         response = self.connection.request(
             action,


[17/20] libcloud git commit: FAM-902 Style fixes

Posted by an...@apache.org.
FAM-902 Style fixes


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/23ec91f4
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/23ec91f4
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/23ec91f4

Branch: refs/heads/trunk
Commit: 23ec91f455fee703b730099544a81cc8fb8d8557
Parents: 9866138
Author: mermoldy <s....@scalr.com>
Authored: Wed May 24 15:00:25 2017 +0300
Committer: Anthony Shaw <an...@apache.org>
Committed: Fri Aug 11 14:59:31 2017 +1000

----------------------------------------------------------------------
 libcloud/compute/drivers/azure_arm.py | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/23ec91f4/libcloud/compute/drivers/azure_arm.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/azure_arm.py b/libcloud/compute/drivers/azure_arm.py
index a225429..37c8815 100644
--- a/libcloud/compute/drivers/azure_arm.py
+++ b/libcloud/compute/drivers/azure_arm.py
@@ -902,7 +902,7 @@ class AzureNodeDriver(NodeDriver):
             a unique LUN.
         :type ex_lun: ``int``
 
-        :param ex_vhd_uri: Attach old-style un-managed disk from VHD
+        :param ex_vhd_uri: Attach old-style unmanaged disk from VHD
             blob. (optional)
         :type ex_vhd_uri: ``str``
 
@@ -931,15 +931,16 @@ class AzureNodeDriver(NodeDriver):
                     "'ex_vhd_resource_group' of the VHD blob is not specified.")
 
             # attach new or existing unmanaged disk
-            is_vhd_exists = self._ex_is_vhd_exists(
+            vhd_exists = self._ex_vhd_exists(
                 ex_vhd_resource_group,
                 ex_vhd_uri)
             new_disk = {
                 'lun': ex_lun,
                 'name': 'unmanaged-vol-{}'.format(str(uuid.uuid4())[0:8]),
-                'createOption': 'attach' if is_vhd_exists else 'empty',
+                'createOption': 'attach' if vhd_exists else 'empty',
                 'vhd': {'uri': ex_vhd_uri},
-                'diskSizeGB': volume.size}
+                'diskSizeGB': volume.size
+            }
         else:
             # attach existing managed disk
             new_disk = {
@@ -1912,7 +1913,7 @@ class AzureNodeDriver(NodeDriver):
         except ObjectDoesNotExistError:
             return True
 
-    def _ex_is_vhd_exists(self, resource_group, vhd_uri):
+    def _ex_vhd_exists(self, resource_group, vhd_uri):
         """
         Check if VHD by given ``vhd_uri`` exists
 


[12/20] libcloud git commit: FAM-690 Codereview fixes.

Posted by an...@apache.org.
FAM-690 Codereview fixes.


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/a3fd0171
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/a3fd0171
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/a3fd0171

Branch: refs/heads/trunk
Commit: a3fd017153e4885cee50f21e201c707a2db1f60c
Parents: c0c6e56
Author: mermoldy <s....@scalr.com>
Authored: Mon Mar 13 12:12:45 2017 +0200
Committer: Anthony Shaw <an...@apache.org>
Committed: Fri Aug 11 14:59:31 2017 +1000

----------------------------------------------------------------------
 libcloud/compute/drivers/azure_arm.py | 67 +++++++++++++-----------------
 1 file changed, 29 insertions(+), 38 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/a3fd0171/libcloud/compute/drivers/azure_arm.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/azure_arm.py b/libcloud/compute/drivers/azure_arm.py
index cc5f370..07fc28e 100644
--- a/libcloud/compute/drivers/azure_arm.py
+++ b/libcloud/compute/drivers/azure_arm.py
@@ -191,6 +191,13 @@ class AzureNodeDriver(NodeDriver):
         "australiasoutheast": "Victoria, Australia"
     }
 
+    SNAPSHOT_STATE_MAP = {
+        'creating': VolumeSnapshotState.CREATING,
+        'updating': VolumeSnapshotState.UPDATING,
+        'succeeded': VolumeSnapshotState.AVAILABLE,
+        'failed': VolumeSnapshotState.ERROR
+    }
+
     def __init__(self, tenant_id, subscription_id, key, secret,
                  secure=True, host=None, port=None,
                  api_version=None, region=None, **kwargs):
@@ -895,10 +902,11 @@ class AzureNodeDriver(NodeDriver):
         if ex_lun is None:
             # find the smallest unused logical unit number
             used_luns = [disk['lun'] for disk in disks]
-            for lun in range(0, 63):
-                if lun not in used_luns:
-                    ex_lun = lun
-                    break
+            free_luns = [lun for lun in range(0, 63) if lun not in used_luns]
+            if len(free_luns) > 0:
+                ex_lun = free_luns[0]
+            else:
+                raise LibcloudError("No LUN available to attach new disk.")
 
         disks.append({
             'lun': ex_lun,
@@ -937,21 +945,11 @@ class AzureNodeDriver(NodeDriver):
         disks = ex_node.extra['properties']['storageProfile']['dataDisks']
 
         # remove volume from `properties.storageProfile.dataDisks`
-        disk_index = None
-        for index, disk in enumerate(disks):
-            if 'managedDisk' in disk:
-                if volume.id == disk['managedDisk'].get('id'):
-                    disk_index = index
-            elif 'name' in disk:
-                if volume.name == disk['name']:
-                    disk_index = index
-        if disk_index is None:
-            raise LibcloudError((
-                "A disk with id {} does not found among managed disks "
-                "attached to an instance ({})."
-            ).format(volume.id, ex_node.id))
-        else:
-            del disks[disk_index]
+        disks[:] = [
+            disk for disk in disks if
+            disk.get('name') != volume.name and
+            disk.get('managedDisk', {}).get('id') != volume.id
+        ]
 
         self.connection.request(
             action,
@@ -1176,19 +1174,10 @@ class AzureNodeDriver(NodeDriver):
         extra['source_id'] = properties['creationData']['sourceUri']
         if '/providers/Microsoft.Compute/disks/' in extra['source_id']:
             extra['volume_id'] = extra['source_id']
-
-        provisioning_state = properties.get('provisioningState', '').lower()
-        if provisioning_state == 'creating':
-            state = VolumeSnapshotState.CREATING
-        elif provisioning_state == 'updating':
-            state = VolumeSnapshotState.UPDATING
-        elif provisioning_state == 'succeeded':
-            state = VolumeSnapshotState.AVAILABLE
-        elif provisioning_state == 'failed':
-            state = VolumeSnapshotState.ERROR
-        else:
-            state = VolumeSnapshotState.UNKNOWN
-
+        state = self.SNAPSHOT_STATE_MAP.get(
+            properties.get('provisioningState', '').lower(),
+            VolumeSnapshotState.UNKNOWN
+        )
         try:
             created_at = iso8601.parse_date(properties.get('timeCreated'))
         except (TypeError, ValueError, iso8601.ParseError):
@@ -1221,8 +1210,10 @@ class AzureNodeDriver(NodeDriver):
         """
         Delete a resource.
         """
+        if not isinstance(resource, basestring):
+            resource = resource.id
         self.connection.request(
-            resource.id,
+            resource,
             method='DELETE',
             params={
                 'api-version': RESOURCE_API_VERSION
@@ -1480,25 +1471,25 @@ class AzureNodeDriver(NodeDriver):
         return [AzureSubnet(net["id"], net["name"], net["properties"])
                 for net in r.object["value"]]
 
-    def ex_list_nics(self, ex_resource_group=None):
+    def ex_list_nics(self, resource_group=None):
         """
         List available virtual network interface controllers
         in a resource group
 
-        :param ex_resource_group: List NICS in a specific resource group
+        :param resource_group: List NICS in a specific resource group
             containing the NICs(optional).
-        :type ex_resource_group: ``str``
+        :type resource_group: ``str``
 
         :return: A list of NICs.
         :rtype: ``list`` of :class:`.AzureNic`
         """
-        if ex_resource_group is None:
+        if resource_group is None:
             action = "/subscriptions/%s/providers/Microsoft.Network" \
                      "/networkInterfaces" % self.subscription_id
         else:
             action = "/subscriptions/%s/resourceGroups/%s/providers" \
                      "/Microsoft.Network/networkInterfaces" % \
-                     (self.subscription_id, ex_resource_group)
+                     (self.subscription_id, resource_group)
         r = self.connection.request(
             action,
             params={"api-version": RESOURCE_API_VERSION})


[02/20] libcloud git commit: FAM-902 Added vhd_resource_group parameter to 'attach_volume'

Posted by an...@apache.org.
FAM-902 Added vhd_resource_group parameter to 'attach_volume'


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/9866138a
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/9866138a
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/9866138a

Branch: refs/heads/trunk
Commit: 9866138af52eb2da8047bf8dc3e395ed0a355a45
Parents: 439e4dc
Author: mermoldy <s....@scalr.com>
Authored: Wed May 24 13:03:58 2017 +0300
Committer: Anthony Shaw <an...@apache.org>
Committed: Fri Aug 11 14:59:31 2017 +1000

----------------------------------------------------------------------
 libcloud/compute/drivers/azure_arm.py | 52 ++++++++++++++++++++----------
 1 file changed, 35 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/9866138a/libcloud/compute/drivers/azure_arm.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/azure_arm.py b/libcloud/compute/drivers/azure_arm.py
index eed44d0..a225429 100644
--- a/libcloud/compute/drivers/azure_arm.py
+++ b/libcloud/compute/drivers/azure_arm.py
@@ -886,9 +886,10 @@ class AzureNodeDriver(NodeDriver):
         )
         return [self._to_volume(volume) for volume in response.object['value']]
 
-    def attach_volume(self, node, volume, ex_lun=None, ex_vhd_uri=None, **ex_kwargs):
+    def attach_volume(self, node, volume, ex_lun=None,
+                      ex_vhd_uri=None, ex_vhd_resource_group=None, **ex_kwargs):
         """
-        Attach a managed volume to node.
+        Attach a volume to node.
 
         :param node: A node to attach volume.
         :type node: :class:`Node`
@@ -905,6 +906,10 @@ class AzureNodeDriver(NodeDriver):
             blob. (optional)
         :type ex_vhd_uri: ``str``
 
+        :param ex_vhd_resource_group: Storage account resource group name.
+            (required for ``ex_vhd_uri``)
+        :type ex_vhd_resource_group: ``str``
+
         :rtype: ``bool``
         """
         action = node.extra['id']
@@ -921,23 +926,26 @@ class AzureNodeDriver(NodeDriver):
                 raise LibcloudError("No LUN available to attach new disk.")
 
         if ex_vhd_uri is not None:
+            if ex_vhd_resource_group is None:
+                raise AttributeError(
+                    "'ex_vhd_resource_group' of the VHD blob is not specified.")
+
             # attach new or existing unmanaged disk
-            resource_group = node.id.split('/')[4]
-            is_vhd_exists = self._ex_is_vhd_exists(resource_group, ex_vhd_uri)
+            is_vhd_exists = self._ex_is_vhd_exists(
+                ex_vhd_resource_group,
+                ex_vhd_uri)
             new_disk = {
                 'lun': ex_lun,
                 'name': 'unmanaged-vol-{}'.format(str(uuid.uuid4())[0:8]),
                 'createOption': 'attach' if is_vhd_exists else 'empty',
                 'vhd': {'uri': ex_vhd_uri},
-                'diskSizeGB': volume.size
-            }
+                'diskSizeGB': volume.size}
         else:
             # attach existing managed disk
             new_disk = {
                 'lun': ex_lun,
                 'createOption': 'attach',
-                'managedDisk': {'id': volume.id}
-            }
+                'managedDisk': {'id': volume.id}}
 
         disks.append(new_disk)
         self.connection.request(
@@ -953,8 +961,7 @@ class AzureNodeDriver(NodeDriver):
                     }
                 },
                 'location': location
-            }
-        )
+            })
         return True
 
     def detach_volume(self, volume, ex_node=None):
@@ -1905,9 +1912,20 @@ class AzureNodeDriver(NodeDriver):
         except ObjectDoesNotExistError:
             return True
 
-    def _ex_is_vhd_exists(self, resource_group, uri):
+    def _ex_is_vhd_exists(self, resource_group, vhd_uri):
+        """
+        Check if VHD by given ``vhd_uri`` exists
+
+        :param resource_group: Storage account resource group name.
+        :type: ``str``
+
+        :param vhd_uri: Virtual hard disk's uri.
+        :type: ``str``
+
+        :rtype: ``bool``
+        """
         try:
-            storage_account, blob_container, blob = _split_blob_uri(uri)
+            storage_account, blob_container, blob = _split_blob_uri(vhd_uri)
             keys = self.ex_get_storage_account_keys(
                 resource_group, storage_account)
             blob_driver = AzureBlobsStorageDriver(
@@ -2018,8 +2036,8 @@ class AzureNodeDriver(NodeDriver):
 
 
 def _split_blob_uri(uri):
-    uri = uri.split("/")
-    storageAccount = uri[2].split(".")[0]
-    blobContainer = uri[3]
-    blob = '/'.join(uri[4:])
-    return (storageAccount, blobContainer, blob)
+    uri = uri.split('/')
+    storage_account = uri[2].split('.')[0]
+    blob_container = uri[3]
+    blob_name = '/'.join(uri[4:])
+    return storage_account, blob_container, blob_name


[09/20] libcloud git commit: FAM-690 WIP

Posted by an...@apache.org.
FAM-690 WIP


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/5352e710
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/5352e710
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/5352e710

Branch: refs/heads/trunk
Commit: 5352e710350939539878aae879c2bd687f401c3d
Parents: 432145f
Author: mermoldy <s....@scalr.com>
Authored: Thu Mar 9 14:19:59 2017 +0200
Committer: Anthony Shaw <an...@apache.org>
Committed: Fri Aug 11 14:59:31 2017 +1000

----------------------------------------------------------------------
 libcloud/compute/drivers/azure_arm.py | 74 +++++++++++++++++-------------
 1 file changed, 41 insertions(+), 33 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/5352e710/libcloud/compute/drivers/azure_arm.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/azure_arm.py b/libcloud/compute/drivers/azure_arm.py
index 375d432..3326a74 100644
--- a/libcloud/compute/drivers/azure_arm.py
+++ b/libcloud/compute/drivers/azure_arm.py
@@ -169,7 +169,6 @@ class AzureNodeDriver(NodeDriver):
     type = Provider.AZURE_ARM
     features = {'create_node': ['ssh_key', 'password']}
 
-
     # The API doesn't provide state or country information, so fill it in.
     # Information from https://azure.microsoft.com/en-us/regions/
     _location_to_country = {
@@ -397,7 +396,8 @@ class AzureNodeDriver(NodeDriver):
                     ex_nic=None,
                     ex_tags={},
                     ex_customdata="",
-                    ex_use_managed_disks=False):
+                    ex_use_managed_disks=False,
+                    ex_storage_account_type="Standard_LRS"):
         """Create a new node instance. This instance will be started
         automatically.
 
@@ -495,6 +495,10 @@ class AzureNodeDriver(NodeDriver):
             in all regions.
         :type ex_use_managed_disks: ``bool``
 
+        :param ex_storage_account_type: The Storage Account type,
+            ``Standard_LRS``(HDD disks) or ``Premium_LRS``(SSD disks).
+        :type ex_storage_account_type: str
+
         :return: The newly created node.
         :rtype: :class:`.Node`
         """
@@ -523,25 +527,25 @@ class AzureNodeDriver(NodeDriver):
                  "/Microsoft.Compute/virtualMachines/%s" % \
                  (self.subscription_id, ex_resource_group, name)
 
-        n = 0
-        while True:
-            try:
-                instance_vhd = "https://%s.blob%s" \
-                               "/%s/%s-os_%i.vhd" \
-                               % (ex_storage_account,
-                                  self.connection.storage_suffix,
-                                  ex_blob_container,
-                                  name,
-                                  n)
-                self._ex_delete_old_vhd(ex_resource_group, instance_vhd)
-                break
-            except LibcloudError:
-                n += 1
+        def _get_instance_vhd():
+            n = 0
+            while True:
+                try:
+                    instance_vhd = "https://%s.blob.core.windows.net" \
+                                   "/%s/%s-os_%i.vhd" \
+                                   % (ex_storage_account,
+                                      ex_blob_container,
+                                      name,
+                                      n)
+                    self._ex_delete_old_vhd(ex_resource_group, instance_vhd)
+                    return instance_vhd
+                except LibcloudError:
+                    n += 1
 
         if isinstance(image, AzureVhdImage):
             storage_profile = {
                 "osDisk": {
-                    "name": "virtualmachine-osDisk",
+                    "name": name,
                     "osType": "linux",
                     "caching": "ReadWrite",
                     "createOption": "FromImage",
@@ -549,10 +553,14 @@ class AzureNodeDriver(NodeDriver):
                         "uri": image.id
                     },
                     "vhd": {
-                        "uri": instance_vhd
+                        "uri": _get_instance_vhd(),
                     }
                 }
             }
+            if ex_use_managed_disks:
+                raise LibcloudError(
+                    "Creating managed OS disk from %s image "
+                    "type is not supported." % type(image))
         elif isinstance(image, AzureImage):
             storage_profile = {
                 "imageReference": {
@@ -562,25 +570,24 @@ class AzureNodeDriver(NodeDriver):
                     "version": image.version
                 },
                 "osDisk": {
-                    "name": "virtualmachine-osDisk",
-                    "vhd": {
-                        "uri": instance_vhd
-                    },
+                    "name": name,
+                    "osType": "linux",
                     "caching": "ReadWrite",
                     "createOption": "FromImage"
                 }
             }
             if ex_use_managed_disks:
-                storage_profile["osDisk"] = {
-                    "name": name,
-                    "createOption": "FromImage",
-                    "caching": "ReadWrite",
+                storage_profile["osDisk"]["managedDisk"] = {
+                    "storageAccountType": ex_storage_account_type
+                }
+            else:
+                storage_profile["osDisk"]["vhd"] = {
+                    "uri": _get_instance_vhd()
                 }
         else:
             raise LibcloudError(
-                "Unknown image type %s,"
-                "expected one of AzureImage, AzureVhdImage",
-                type(image))
+                "Unknown image type %s, expected one of AzureImage, "
+                "AzureVhdImage." % type(image))
 
         data = {
             "id": target,
@@ -636,10 +643,11 @@ class AzureNodeDriver(NodeDriver):
             raise ValueError(
                 "Must provide NodeAuthSSHKey or NodeAuthPassword in auth")
 
-        r = self.connection.request(target,
-                                    params={"api-version": RESOURCE_API_VERSION},
-                                    data=data,
-                                    method="PUT")
+        r = self.connection.request(
+            target,
+            params={"api-version": RESOURCE_API_VERSION},
+            data=data,
+            method="PUT")
 
         node = self._to_node(r.object)
         node.size = size


[07/20] libcloud git commit: FAM-690 Fixes

Posted by an...@apache.org.
FAM-690 Fixes


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/cbf1d5a6
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/cbf1d5a6
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/cbf1d5a6

Branch: refs/heads/trunk
Commit: cbf1d5a614d9b8a09f859cbe9a8dba140d8d117b
Parents: 6078d85
Author: mermoldy <s....@scalr.com>
Authored: Wed Mar 1 19:33:04 2017 +0200
Committer: Anthony Shaw <an...@apache.org>
Committed: Fri Aug 11 14:59:31 2017 +1000

----------------------------------------------------------------------
 libcloud/compute/drivers/azure_arm.py | 45 +++++++++++++-----------------
 1 file changed, 20 insertions(+), 25 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/cbf1d5a6/libcloud/compute/drivers/azure_arm.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/azure_arm.py b/libcloud/compute/drivers/azure_arm.py
index 57117f3..632d9a7 100644
--- a/libcloud/compute/drivers/azure_arm.py
+++ b/libcloud/compute/drivers/azure_arm.py
@@ -36,7 +36,7 @@ from libcloud.storage.types import ObjectDoesNotExistError
 from libcloud.common.exceptions import BaseHTTPError
 from libcloud.storage.drivers.azure_blobs import AzureBlobsStorageDriver
 from libcloud.utils.py3 import basestring
-from libcloud.utils.iso8601 import parse_date
+from libcloud.utils import iso8601
 
 
 RESOURCE_API_VERSION = '2016-04-30-preview'
@@ -802,23 +802,21 @@ class AzureNodeDriver(NodeDriver):
             volume_name=name,
         )
         tags = ex_tags if ex_tags is not None else {}
+
+        creation_data = {
+            'createOption': 'Empty'
+        } if snapshot is None else {
+            'createOption': 'Copy',
+            'sourceUri': snapshot.id
+        }
         data = {
             'location': location.id,
             'tags': tags,
             'properties': {
-                'creationData': {
-                    'createOption': 'Empty'
-                },
+                'creationData': creation_data,
                 'diskSizeGB': size
             }
         }
-        if snapshot is not None:
-            data['properties']['creationData'] = {
-                'createOption': 'Copy',
-                'sourceUri': {
-                    'id': snapshot.id
-                }
-            }
 
         response = self.connection.request(
             action,
@@ -868,7 +866,7 @@ class AzureNodeDriver(NodeDriver):
 
     def attach_volume(self, node, volume, device=None, ex_lun=None):
         """
-        Attach volume to node.
+        Attach a managed volume to node.
 
         :param node: A node to attach volume.
         :type node: :class:`Node`
@@ -906,7 +904,7 @@ class AzureNodeDriver(NodeDriver):
             }
         })
 
-        response = self.connection.request(
+        self.connection.request(
             action,
             method='PUT',
             params={
@@ -921,13 +919,11 @@ class AzureNodeDriver(NodeDriver):
                 'location': location
             }
         )
-
-        disks = response.object['properties']['storageProfile']['dataDisks']
-        return volume.id in [disk['managedDisk']['id'] for disk in disks]
+        return True
 
     def detach_volume(self, volume, ex_node=None):
         """
-        Detach a volume from a node.
+        Detach a managed volume from a node.
         """
         if ex_node is None:
             raise ValueError("Must provide `ex_node` value")
@@ -938,10 +934,11 @@ class AzureNodeDriver(NodeDriver):
 
         # remove volume from `properties.storageProfile.dataDisks`
         for index, disk in enumerate(disks):
-            if volume.id == disk['managedDisk']['id']:
-                del disks[index]
+            if 'managedDisk' in disk:
+                if volume.id == disk['managedDisk'].get('id'):
+                    del disks[index]
 
-        response = self.connection.request(
+        self.connection.request(
             action,
             method='PUT',
             params={
@@ -956,9 +953,7 @@ class AzureNodeDriver(NodeDriver):
                 'location': location
             }
         )
-
-        disks = response.object['properties']['storageProfile']['dataDisks']
-        return volume.id not in [disk['managedDisk']['id'] for disk in disks]
+        return True
 
     def destroy_volume(self, volume):
         """
@@ -1178,8 +1173,8 @@ class AzureNodeDriver(NodeDriver):
             state = VolumeSnapshotState.UNKNOWN
 
         try:
-            created_at = parse_date(snapshot_obj['properties']['timeCreated'])
-        except ValueError:
+            created_at = iso8601.parse_date(properties.get('timeCreated'))
+        except (TypeError, ValueError, iso8601.ParseError):
             created_at = None
 
         if snapshot_id is None \


[04/20] libcloud git commit: FAM-690 Added 'updating' state

Posted by an...@apache.org.
FAM-690 Added 'updating' state


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/432145f6
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/432145f6
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/432145f6

Branch: refs/heads/trunk
Commit: 432145f6d45b7a88862999937ce0d29cd07e896e
Parents: 774b097
Author: mermoldy <s....@scalr.com>
Authored: Tue Mar 7 19:37:11 2017 +0200
Committer: Anthony Shaw <an...@apache.org>
Committed: Fri Aug 11 14:59:31 2017 +1000

----------------------------------------------------------------------
 libcloud/compute/drivers/azure_arm.py | 11 ++++++++---
 libcloud/compute/types.py             |  3 +++
 2 files changed, 11 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/432145f6/libcloud/compute/drivers/azure_arm.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/azure_arm.py b/libcloud/compute/drivers/azure_arm.py
index 6a43d09..375d432 100644
--- a/libcloud/compute/drivers/azure_arm.py
+++ b/libcloud/compute/drivers/azure_arm.py
@@ -1108,8 +1108,11 @@ class AzureNodeDriver(NodeDriver):
 
         provisioning_state = properties.get('provisioningState', '').lower()
         disk_state = properties.get('diskState', '').lower()
-        if provisioning_state in ('creating', 'updating'):
+
+        if provisioning_state == 'creating':
             state = StorageVolumeState.CREATING
+        elif provisioning_state == 'updating':
+            state = StorageVolumeState.UPDATING
         elif provisioning_state == 'succeeded':
             if disk_state in ('attached', 'reserved', 'activesas'):
                 state = StorageVolumeState.INUSE
@@ -1174,8 +1177,10 @@ class AzureNodeDriver(NodeDriver):
             extra['volume_id'] = extra['source_id']
 
         provisioning_state = properties.get('provisioningState', '').lower()
-        if provisioning_state in ('creating', 'updating'):
+        if provisioning_state == 'creating':
             state = VolumeSnapshotState.CREATING
+        elif provisioning_state == 'updating':
+            state = VolumeSnapshotState.UPDATING
         elif provisioning_state == 'succeeded':
             state = VolumeSnapshotState.AVAILABLE
         elif provisioning_state == 'failed':
@@ -1884,7 +1889,7 @@ class AzureNodeDriver(NodeDriver):
                     state = NodeState.ERROR
                     break
                 elif status["code"] == "ProvisioningState/updating":
-                    state = NodeState.RECONFIGURING
+                    state = NodeState.UPDATING
                     break
                 elif status["code"] == "ProvisioningState/succeeded":
                     pass

http://git-wip-us.apache.org/repos/asf/libcloud/blob/432145f6/libcloud/compute/types.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/types.py b/libcloud/compute/types.py
index 15205dc..deae506 100644
--- a/libcloud/compute/types.py
+++ b/libcloud/compute/types.py
@@ -286,6 +286,7 @@ class NodeState(Type):
     RECONFIGURING = 'reconfiguring'
     MIGRATING = 'migrating'
     NORMAL = 'normal'
+    UPDATING = 'updating'
 
 
 class StorageVolumeState(Type):
@@ -302,6 +303,7 @@ class StorageVolumeState(Type):
     ATTACHING = 'attaching'
     UNKNOWN = 'unknown'
     MIGRATING = 'migrating'
+    UPDATING = 'updating'
 
 
 class VolumeSnapshotState(Type):
@@ -314,6 +316,7 @@ class VolumeSnapshotState(Type):
     DELETING = 'deleting'
     RESTORING = 'restoring'
     UNKNOWN = 'unknown'
+    UPDATING = 'updating'
 
 
 class Architecture(object):