libcloud-notifications mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From to...@apache.org
Subject [1/2] libcloud git commit: Add the following new methods to the Linode driver: ex_list_volumes, ex_create_volume, ex_destroy_volume.
Date Sat, 21 Feb 2015 23:58:40 GMT
Repository: libcloud
Updated Branches:
  refs/heads/trunk b37df1281 -> 193c42f21


Add the following new methods to the Linode driver: ex_list_volumes,
ex_create_volume, ex_destroy_volume.

Closes #430

Signed-off-by: Tomaz Muraus <tomaz@apache.org>


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

Branch: refs/heads/trunk
Commit: d9efecdb227c9d6167d35b71c5b361d3bb356963
Parents: 26ddc9a
Author: Wojciech Wirkijowski <wojciech@wirkijowski.pl>
Authored: Sun Nov 9 12:46:54 2014 +0000
Committer: Tomaz Muraus <tomaz@apache.org>
Committed: Sun Feb 22 00:24:58 2015 +0100

----------------------------------------------------------------------
 CHANGES.rst                                     |   5 +
 libcloud/common/linode.py                       |   3 +
 libcloud/compute/drivers/linode.py              | 141 ++++++++++++++++++-
 .../fixtures/linode/_linode_disk_list.json      |  28 ++++
 libcloud/test/compute/test_linode.py            |  44 +++++-
 5 files changed, 213 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/d9efecdb/CHANGES.rst
----------------------------------------------------------------------
diff --git a/CHANGES.rst b/CHANGES.rst
index 976823f..b8baa23 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -29,6 +29,11 @@ Compute
   (LIBCLOUD-668, GITHUB-462)
   [Allard Hoeve]
 
+- Add the following new methods to the Linode driver: ``ex_list_volumes``,
+  ``ex_create_volume``, ``ex_destroy_volume``.
+  (LIBCLOUD-649, GITHUB-430)
+  [Wojciech Wirkijowski]
+
 Changes with Apache Libcloud 0.17.0
 -----------------------------------
 

http://git-wip-us.apache.org/repos/asf/libcloud/blob/d9efecdb/libcloud/common/linode.py
----------------------------------------------------------------------
diff --git a/libcloud/common/linode.py b/libcloud/common/linode.py
index aba75f0..c991695 100644
--- a/libcloud/common/linode.py
+++ b/libcloud/common/linode.py
@@ -42,6 +42,9 @@ LINODE_PLAN_IDS = {1024: '1',
                    65536: '10',
                    98304: '12'}
 
+# Available filesystems for disk creation
+LINODE_DISK_FILESYSTEMS = ['ext3', 'ext4', 'swap', 'raw']
+
 
 class LinodeException(Exception):
     """Error originating from the Linode API

http://git-wip-us.apache.org/repos/asf/libcloud/blob/d9efecdb/libcloud/compute/drivers/linode.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/linode.py b/libcloud/compute/drivers/linode.py
index 4960f29..c3a9642 100644
--- a/libcloud/compute/drivers/linode.py
+++ b/libcloud/compute/drivers/linode.py
@@ -42,11 +42,12 @@ from copy import copy
 from libcloud.utils.py3 import PY3
 
 from libcloud.common.linode import (API_ROOT, LinodeException,
-                                    LinodeConnection, LINODE_PLAN_IDS)
+                                    LinodeConnection, LINODE_PLAN_IDS,
+                                    LINODE_DISK_FILESYSTEMS)
 from libcloud.compute.types import Provider, NodeState
 from libcloud.compute.base import NodeDriver, NodeSize, Node, NodeLocation
 from libcloud.compute.base import NodeAuthPassword, NodeAuthSSHKey
-from libcloud.compute.base import NodeImage
+from libcloud.compute.base import NodeImage, StorageVolume
 
 
 class LinodeNodeDriver(NodeDriver):
@@ -64,6 +65,8 @@ class LinodeNodeDriver(NodeDriver):
         list_sizes              avail.linodeplans
         list_images             avail.distributions
         list_locations          avail.datacenters
+        list_volumes            linode.disk.list
+        destroy_volume          linode.disk.delete
 
     For more information on the Linode API, be sure to read the reference:
 
@@ -74,6 +77,7 @@ class LinodeNodeDriver(NodeDriver):
     website = 'http://www.linode.com/'
     connectionCls = LinodeConnection
     _linode_plan_ids = LINODE_PLAN_IDS
+    _linode_disk_filesystems = LINODE_DISK_FILESYSTEMS
     features = {'create_node': ['ssh_key', 'password']}
 
     def __init__(self, key):
@@ -464,7 +468,7 @@ class LinodeNodeDriver(NodeDriver):
         used.
 
         :keyword dc: the datacenter to create Linodes in unless specified
-        :type dc: :class:`NodeLocation`
+        :type    dc: :class:`NodeLocation`
 
         :rtype: ``bool``
         """
@@ -480,6 +484,137 @@ class LinodeNodeDriver(NodeDriver):
         self.datacenter = None
         raise LinodeException(0xFD, "Invalid datacenter (use one of %s)" % dcs)
 
+    def destroy_volume(self, volume):
+        """
+        Destroys disk volume for the Linode. Linode id is to be provided as
+        extra["LinodeId"] whithin :class:`StorageVolume`. It can be retrieved
+        by :meth:`libcloud.compute.drivers.linode.LinodeNodeDriver\
+                 .ex_list_volumes`.
+
+        :param volume: Volume to be destroyed
+        :type volume: :class:`StorageVolume`
+
+        :rtype: ``bool``
+        """
+        if not isinstance(volume, StorageVolume):
+            raise LinodeException(0xFD, "Invalid volume instance")
+
+        if volume.extra["LINODEID"] is None:
+            raise LinodeException(0xFD, "Missing LinodeID")
+
+        params = {
+            "api_action": "linode.disk.delete",
+            "LinodeID": volume.extra["LINODEID"],
+            "DiskID": volume.id,
+        }
+        self.connection.request(API_ROOT, params=params)
+
+        return True
+
+    def ex_create_volume(self, size, name, node, fs_type):
+        """
+        Create disk for the Linode.
+
+        :keyword    size: Size of volume in megabytes (required)
+        :type       size: ``int``
+
+        :keyword    name: Name of the volume to be created
+        :type       name: ``str``
+
+        :keyword    node: Node to attach volume to.
+        :type       node: :class:`Node`
+
+        :keyword    fs_type: The formatted type of this disk. Valid types are:
+                             ext3, ext4, swap, raw
+        :type       fs_type: ``str``
+
+
+        :return: StorageVolume representing the newly-created volume
+        :rtype: :class:`StorageVolume`
+        """
+        # check node
+        if not isinstance(node, Node):
+            raise LinodeException(0xFD, "Invalid node instance")
+
+        # check space available
+        total_space = node.extra['TOTALHD']
+        existing_volumes = self.ex_list_volumes(node)
+        used_space = 0
+        for volume in existing_volumes:
+            used_space = used_space + volume.size
+
+        available_space = total_space - used_space
+        if available_space < size:
+            raise LinodeException(0xFD, "Volume size too big. Available space\
+                    %d" % available_space)
+
+        # check filesystem type
+        if fs_type not in self._linode_disk_filesystems:
+            raise LinodeException(0xFD, "Not valid filesystem type")
+
+        params = {
+            "api_action": "linode.disk.create",
+            "LinodeID": node.id,
+            "Label": name,
+            "Type": fs_type,
+            "Size": size
+        }
+        data = self.connection.request(API_ROOT, params=params).objects[0]
+        volume = data["DiskID"]
+        # Make a volume out of it and hand it back
+        params = {
+            "api_action": "linode.disk.list",
+            "LinodeID": node.id,
+            "DiskID": volume
+        }
+        data = self.connection.request(API_ROOT, params=params).objects[0]
+        return self._to_volumes(data)[0]
+
+    def ex_list_volumes(self, node, disk_id=None):
+        """
+        List existing disk volumes for for given Linode.
+
+        :keyword    node: Node to list disk volumes for. (required)
+        :type       node: :class:`Node`
+
+        :keyword    disk_id: Id for specific disk volume. (optional)
+        :type       disk_id: ``int``
+
+        :rtype: ``list`` of :class:`StorageVolume`
+        """
+        if not isinstance(node, Node):
+            raise LinodeException(0xFD, "Invalid node instance")
+
+        params = {
+            "api_action": "linode.disk.list",
+            "LinodeID": node.id
+        }
+        # Add param if disk_id was specified
+        if disk_id is not None:
+            params["DiskID"] = disk_id
+
+        data = self.connection.request(API_ROOT, params=params).objects[0]
+        return self._to_volumes(data)
+
+    def _to_volumes(self, objs):
+        """
+        Covert returned JSON volumes into StorageVolume instances
+
+        :keyword    objs: ``list`` of JSON dictionaries representing the
+                         StorageVolumes
+        :type       objs: ``list``
+
+        :return: ``list`` of :class:`StorageVolume`s
+        """
+        volumes = {}
+        for o in objs:
+            vid = o["DISKID"]
+            volumes[vid] = vol = StorageVolume(id=vid, name=o["LABEL"],
+                                               size=int(o["SIZE"]),
+                                               driver=self.connection.driver)
+            vol.extra = copy(o)
+        return list(volumes.values())
+
     def _to_nodes(self, objs):
         """Convert returned JSON Linodes into Node instances
 

http://git-wip-us.apache.org/repos/asf/libcloud/blob/d9efecdb/libcloud/test/compute/fixtures/linode/_linode_disk_list.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/linode/_linode_disk_list.json b/libcloud/test/compute/fixtures/linode/_linode_disk_list.json
new file mode 100644
index 0000000..8ec05a9
--- /dev/null
+++ b/libcloud/test/compute/fixtures/linode/_linode_disk_list.json
@@ -0,0 +1,28 @@
+{
+"ERRORARRAY":[],
+"ACTION":"linode.disk.list",
+"DATA":[
+        {
+            "UPDATE_DT":"2009-06-30 13:19:00.0",
+            "DISKID":55319,
+            "LABEL":"test label",
+            "TYPE":"ext3",
+            "LINODEID":8098,
+            "ISREADONLY":0,
+            "STATUS":1,
+            "CREATE_DT":"2008-04-04 10:08:06.0",
+            "SIZE":4096
+        },
+        {
+            "UPDATE_DT":"2009-07-18 12:53:043.0",
+            "DISKID":55320,
+            "LABEL":"256M Swap Image",
+            "TYPE":"swap",
+            "LINODEID":8098,
+            "ISREADONLY":0,
+            "STATUS":1,
+            "CREATE_DT":"2008-04-04 10:08:06.0",
+            "SIZE":256
+        }
+    ]
+}

http://git-wip-us.apache.org/repos/asf/libcloud/blob/d9efecdb/libcloud/test/compute/test_linode.py
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/test_linode.py b/libcloud/test/compute/test_linode.py
index 090e4d8..9a35f07 100644
--- a/libcloud/test/compute/test_linode.py
+++ b/libcloud/test/compute/test_linode.py
@@ -22,7 +22,8 @@ import unittest
 from libcloud.utils.py3 import httplib
 
 from libcloud.compute.drivers.linode import LinodeNodeDriver
-from libcloud.compute.base import Node, NodeAuthPassword, NodeAuthSSHKey
+from libcloud.compute.base import Node, NodeAuthPassword
+from libcloud.compute.base import NodeAuthSSHKey, StorageVolume
 
 from libcloud.test import MockHttp
 from libcloud.test.compute import TestCaseMixin
@@ -95,6 +96,31 @@ class LinodeTest(unittest.TestCase, TestCaseMixin):
                                        auth=NodeAuthPassword("foobar"))
         self.assertTrue(isinstance(node, Node))
 
+    def test_destroy_volume(self):
+        # Will exception on failure
+        node = self.driver.list_nodes()[0]
+        volume = StorageVolume(id=55648, name="test", size=1024,
+                               driver=self.driver, extra={"LINODEID": node.id})
+        self.driver.destroy_volume(volume)
+
+    def test_ex_create_volume(self):
+        # should return a StorageVolume object
+        node = self.driver.list_nodes()[0]
+        volume = self.driver.ex_create_volume(size=4096,
+                                              name="Another test image",
+                                              node=node,
+                                              fs_type="ext4")
+        self.assertTrue(isinstance(volume, StorageVolume))
+
+    def test_ex_list_volumes(self):
+        # should return list of StorageVolume objects
+        node = self.driver.list_nodes()[0]
+        volumes = self.driver.ex_list_volumes(node=node)
+
+        self.assertTrue(isinstance(volumes, list))
+        self.assertTrue(isinstance(volumes[0], StorageVolume))
+        self.assertEqual(len(volumes), 2)
+
 
 class LinodeMockHttp(MockHttp):
     fixtures = ComputeFileFixtures('linode')
@@ -115,10 +141,22 @@ class LinodeMockHttp(MockHttp):
         body = '{"ERRORARRAY":[],"ACTION":"linode.create","DATA":{"LinodeID":8098}}'
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
 
+    def _linode_disk_create(self, method, url, body, headers):
+        body = '{"ERRORARRAY":[],"ACTION":"linode.disk.create","DATA":{"JobID":1298,"DiskID":55647}}'
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _linode_disk_delete(self, method, url, body, headers):
+        body = '{"ERRORARRAY":[],"ACTION":"linode.disk.delete","DATA":{"JobID":1298,"DiskID":55648}}'
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
     def _linode_disk_createfromdistribution(self, method, url, body, headers):
         body = '{"ERRORARRAY":[],"ACTION":"linode.disk.createFromDistribution","DATA":{"JobID":1298,"DiskID":55647}}'
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
 
+    def _linode_disk_list(self, method, url, body, headers):
+        body = self.fixtures.load('_linode_disk_list.json')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
     def _linode_delete(self, method, url, body, headers):
         body = '{"ERRORARRAY":[],"ACTION":"linode.delete","DATA":{"LinodeID":8098}}'
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
@@ -135,10 +173,6 @@ class LinodeMockHttp(MockHttp):
         body = self.fixtures.load('_avail_kernels.json')
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
 
-    def _linode_disk_create(self, method, url, body, headers):
-        body = '{"ERRORARRAY":[],"ACTION":"linode.disk.create","DATA":{"JobID":1299,"DiskID":55648}}'
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
     def _linode_boot(self, method, url, body, headers):
         body = '{"ERRORARRAY":[],"ACTION":"linode.boot","DATA":{"JobID":1300}}'
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])


Mime
View raw message