Author: tomaz
Date: Fri Jun 8 21:53:52 2012
New Revision: 1348260
URL: http://svn.apache.org/viewvc?rev=1348260&view=rev
Log:
Add extenstion methods for block storage volume management to the
CloudStack driver. Contributed by Gabriel Reid, part of LIBCLOUD-208.
Added:
libcloud/trunk/test/compute/fixtures/cloudstack/attachVolume_default.json
libcloud/trunk/test/compute/fixtures/cloudstack/attachVolume_default.json.rej
libcloud/trunk/test/compute/fixtures/cloudstack/createVolume_default.json
libcloud/trunk/test/compute/fixtures/cloudstack/createVolume_withcustomdisksize.json
libcloud/trunk/test/compute/fixtures/cloudstack/listDiskOfferings_default.json
libcloud/trunk/test/compute/fixtures/cloudstack/listDiskOfferings_withcustomdisksize.json
libcloud/trunk/test/compute/fixtures/cloudstack/listZones_withcustomdisksize.json
libcloud/trunk/test/compute/fixtures/cloudstack/queryAsyncJobResult_attachvolumejob.json
libcloud/trunk/test/compute/fixtures/cloudstack/queryAsyncJobResult_createvolumejob.json
Modified:
libcloud/trunk/CHANGES
libcloud/trunk/libcloud/compute/drivers/cloudstack.py
libcloud/trunk/test/compute/test_cloudstack.py
Modified: libcloud/trunk/CHANGES
URL:
http://svn.apache.org/viewvc/libcloud/trunk/CHANGES?rev=1348260&r1=1348259&r2=1348260&view=diff
==============================================================================
--- libcloud/trunk/CHANGES (original)
+++ libcloud/trunk/CHANGES Fri Jun 8 21:53:52 2012
@@ -38,6 +38,10 @@ Changes with Apache Libcloud in developm
LIBCLOUD-207
[Gabriel Reid]
+ - Add extenstion methods for block storage volume management to the
+ CloudStack driver. ; LIBCLOUD-208
+ [Gabriel Reid]
+
*) DNS
- Add support for GEO RecordType to Zerigo driver. ; LIBCLOUD-203
Modified: libcloud/trunk/libcloud/compute/drivers/cloudstack.py
URL:
http://svn.apache.org/viewvc/libcloud/trunk/libcloud/compute/drivers/cloudstack.py?rev=1348260&r1=1348259&r2=1348260&view=diff
==============================================================================
--- libcloud/trunk/libcloud/compute/drivers/cloudstack.py (original)
+++ libcloud/trunk/libcloud/compute/drivers/cloudstack.py Fri Jun 8 21:53:52
2012
@@ -78,6 +78,30 @@ class CloudStackForwardingRule(object):
return self.__class__ is other.__class__ and self.id == other.id
+class CloudStackDiskOffering(object):
+ """A disk offering within CloudStack."""
+
+ def __init__(self, id, name, size, customizable):
+ self.id = id
+ self.name = name
+ self.size = size
+ self.customizable = customizable
+
+ def __eq__(self, other):
+ return self.__class__ is other.__class__ and self.id == other.id
+
+
+class CloudStackVolume(object):
+ """A storage volume within CloudStack."""
+
+ def __init__(self, id, name):
+ self.id = id
+ self.name = name
+
+ def __eq__(self, other):
+ return self.__class__ is other.__class__ and self.id == other.id
+
+
class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver):
"""Driver for the CloudStack API.
@@ -247,6 +271,78 @@ class CloudStackNodeDriver(CloudStackDri
self._async_request('rebootVirtualMachine', id=node.id)
return True
+ def ex_list_disk_offerings(self):
+ """Fetch a list of all available disk offerings."""
+
+ diskOfferings = []
+
+ diskOfferResponse = self._sync_request('listDiskOfferings')
+ for diskOfferDict in diskOfferResponse.get('diskoffering', ()):
+ diskOfferings.append(
+ CloudStackDiskOffering(
+ id=diskOfferDict['id'],
+ name=diskOfferDict['name'],
+ size=diskOfferDict['disksize'],
+ customizable=diskOfferDict['iscustomized']))
+
+ return diskOfferings
+
+ def ex_create_volume(self, name, location, size):
+ """
+ Create a new detached storage volume.
+
+ @type name: C{str}
+ @param name: Name to be given to the created volume
+
+ @type location: L{NodeLocation}
+ @param location: The location where the volume is to be created
+
+ @type size: C{int}
+ @param location: The size of the volume to be created, in GB
+
+ @returns: The newly-created detached volume
+ """
+
+ for diskOffering in self.ex_list_disk_offerings():
+ if diskOffering.size == size or diskOffering.customizable:
+ break
+ else:
+ raise LibcloudError(
+ "Disk offering with size=%s not found" % size)
+
+ extraParams = dict()
+ if diskOffering.customizable:
+ extraParams['size'] = size
+
+ requestResult = self._async_request('createVolume',
+ name=name,
+ diskOfferingId=diskOffering.id,
+ zoneId=location.id,
+ **extraParams)
+
+ volumeResponse = requestResult['volume']
+
+ return CloudStackVolume(
+ id = volumeResponse['id'],
+ name = volumeResponse['name'])
+
+
+ def ex_attach_volume(self, node, volume):
+ """
+ Attach a storage volume to a node.
+
+ @type node: L{CloudStackNode}
+ @param node: The node to which the volume is to be attached
+
+ @type volume: L{CloudStackVolume}
+ @param volume: The volume to be attached
+ """
+
+ self._async_request('attachVolume',
+ id=volume.id,
+ virtualMachineId=node.id)
+ return True
+
def ex_allocate_public_ip(self, node):
"Allocate a public IP and bind it to a node."
Added: libcloud/trunk/test/compute/fixtures/cloudstack/attachVolume_default.json
URL:
http://svn.apache.org/viewvc/libcloud/trunk/test/compute/fixtures/cloudstack/attachVolume_default.json?rev=1348260&view=auto
==============================================================================
--- libcloud/trunk/test/compute/fixtures/cloudstack/attachVolume_default.json
(added)
+++ libcloud/trunk/test/compute/fixtures/cloudstack/attachVolume_default.json
Fri Jun 8 21:53:52 2012
@@ -0,0 +1 @@
+{ "attachvolumeresponse" : {"jobid":"attachvolumejob"} }
Added:
libcloud/trunk/test/compute/fixtures/cloudstack/attachVolume_default.json.rej
URL:
http://svn.apache.org/viewvc/libcloud/trunk/test/compute/fixtures/cloudstack/attachVolume_default.json.rej?rev=1348260&view=auto
==============================================================================
---
libcloud/trunk/test/compute/fixtures/cloudstack/attachVolume_default.json.rej
(added)
+++
libcloud/trunk/test/compute/fixtures/cloudstack/attachVolume_default.json.rej
Fri Jun 8 21:53:52 2012
@@ -0,0 +1,4 @@
+--- /dev/null
++++ test/compute/fixtures/cloudstack/attachVolume_default.json
+@@ -0,0 +1 @@
++{ "attachvolumeresponse" : {"jobid":"attachvolumejob"} }
Added: libcloud/trunk/test/compute/fixtures/cloudstack/createVolume_default.json
URL:
http://svn.apache.org/viewvc/libcloud/trunk/test/compute/fixtures/cloudstack/createVolume_default.json?rev=1348260&view=auto
==============================================================================
--- libcloud/trunk/test/compute/fixtures/cloudstack/createVolume_default.json
(added)
+++ libcloud/trunk/test/compute/fixtures/cloudstack/createVolume_default.json
Fri Jun 8 21:53:52 2012
@@ -0,0 +1 @@
+{ "createvolumeresponse" :
{"id":"60338035-92fb-4d27-98d4-b60ad4b38b87","jobid":"createvolumejob"} }
Added:
libcloud/trunk/test/compute/fixtures/cloudstack/createVolume_withcustomdisksize.json
URL:
http://svn.apache.org/viewvc/libcloud/trunk/test/compute/fixtures/cloudstack/createVolume_withcustomdisksize.json?rev=1348260&view=auto
==============================================================================
---
libcloud/trunk/test/compute/fixtures/cloudstack/createVolume_withcustomdisksize.json
(added)
+++
libcloud/trunk/test/compute/fixtures/cloudstack/createVolume_withcustomdisksize.json
Fri Jun 8 21:53:52 2012
@@ -0,0 +1 @@
+{ "createvolumeresponse" :
{"id":"60338035-92fb-4d27-98d4-b60ad4b38b87","jobid":"createvolumejob"} }
Added:
libcloud/trunk/test/compute/fixtures/cloudstack/listDiskOfferings_default.json
URL:
http://svn.apache.org/viewvc/libcloud/trunk/test/compute/fixtures/cloudstack/listDiskOfferings_default.json?rev=1348260&view=auto
==============================================================================
---
libcloud/trunk/test/compute/fixtures/cloudstack/listDiskOfferings_default.json
(added)
+++
libcloud/trunk/test/compute/fixtures/cloudstack/listDiskOfferings_default.json
Fri Jun 8 21:53:52 2012
@@ -0,0 +1 @@
+{ "listdiskofferingsresponse" : { "count":1 ,"diskoffering" : [
{"id":"6345e3b7-227e-4209-8f8c-1f94219696e6","name":"Disk offer
1","displaytext":"Disk offer 1 display
name","disksize":10,"created":"2012-04-24T16:35:55+0200","iscustomized":false}
] } }
Added:
libcloud/trunk/test/compute/fixtures/cloudstack/listDiskOfferings_withcustomdisksize.json
URL:
http://svn.apache.org/viewvc/libcloud/trunk/test/compute/fixtures/cloudstack/listDiskOfferings_withcustomdisksize.json?rev=1348260&view=auto
==============================================================================
---
libcloud/trunk/test/compute/fixtures/cloudstack/listDiskOfferings_withcustomdisksize.json
(added)
+++
libcloud/trunk/test/compute/fixtures/cloudstack/listDiskOfferings_withcustomdisksize.json
Fri Jun 8 21:53:52 2012
@@ -0,0 +1 @@
+{ "listdiskofferingsresponse" : { "count":1 ,"diskoffering" : [
{"id":"6345e3b7-227e-4209-8f8c-1f94219696e6","name":"Disk offer
1","displaytext":"Disk offer 1 display
name","disksize":10,"created":"2012-04-24T16:35:55+0200","iscustomized":true}
] } }
Added:
libcloud/trunk/test/compute/fixtures/cloudstack/listZones_withcustomdisksize.json
URL:
http://svn.apache.org/viewvc/libcloud/trunk/test/compute/fixtures/cloudstack/listZones_withcustomdisksize.json?rev=1348260&view=auto
==============================================================================
---
libcloud/trunk/test/compute/fixtures/cloudstack/listZones_withcustomdisksize.json
(added)
+++
libcloud/trunk/test/compute/fixtures/cloudstack/listZones_withcustomdisksize.json
Fri Jun 8 21:53:52 2012
@@ -0,0 +1 @@
+{ "listzonesresponse" : { "zone" : [
{"id":1,"name":"Sydney","networktype":"Advanced","securitygroupsenabled":false}
] } }
Added:
libcloud/trunk/test/compute/fixtures/cloudstack/queryAsyncJobResult_attachvolumejob.json
URL:
http://svn.apache.org/viewvc/libcloud/trunk/test/compute/fixtures/cloudstack/queryAsyncJobResult_attachvolumejob.json?rev=1348260&view=auto
==============================================================================
---
libcloud/trunk/test/compute/fixtures/cloudstack/queryAsyncJobResult_attachvolumejob.json
(added)
+++
libcloud/trunk/test/compute/fixtures/cloudstack/queryAsyncJobResult_attachvolumejob.json
Fri Jun 8 21:53:52 2012
@@ -0,0 +1 @@
+{ "queryasyncjobresultresponse" :
{"accountid":"be7d76b3-8823-49c0-86e1-29efd9ea1eb0","userid":"a8bd3087-edc1-4e94-8470-6830404b7292","cmd":"com.cloud.api.commands.AttachVolumeCmd","jobstatus":1,"jobprocstatus":0,"jobresultcode":0,"jobresulttype":"object","jobresult":{"volume":{"id":"60338035-92fb-4d27-98d4-b60ad4b38b87","name":"vol-0","zoneid":"58624957-a150-46a3-acbf-4088776161e5","zonename":"EQ-AMS2-Z01","type":"DATADISK","deviceid":5,"virtualmachineid":"ab2c18f6-00a6-43f8-9fe0-efecb3165dd7","vmname":"ab2c18f6-00a6-43f8-9fe0-efecb3165dd7","vmdisplayname":"gre-kickstart","vmstate":"Running","size":10737418240,"created":"2012-06-05T08:47:54+0200","state":"Ready","account":"admin","domainid":"bfc35f83-8589-4e93-9150-d57e8479f772","domain":"ROOT","storagetype":"shared","hypervisor":"KVM","diskofferingid":"6345e3b7-227e-4209-8f8c-1f94219696e6","diskofferingname":"Disk
offering 1","diskofferingdisplaytext":"Disk offering 1 display
name","storage":"Shared Storage CL01","attached
":"2012-06-05T09:17:38+0200","destroyed":false,"isextractable":false}},"created":"2012-06-05T09:17:38+0200","jobid":"e07d6b9b-2b6c-45bd-840b-3c4c3d890168"}
}
Added:
libcloud/trunk/test/compute/fixtures/cloudstack/queryAsyncJobResult_createvolumejob.json
URL:
http://svn.apache.org/viewvc/libcloud/trunk/test/compute/fixtures/cloudstack/queryAsyncJobResult_createvolumejob.json?rev=1348260&view=auto
==============================================================================
---
libcloud/trunk/test/compute/fixtures/cloudstack/queryAsyncJobResult_createvolumejob.json
(added)
+++
libcloud/trunk/test/compute/fixtures/cloudstack/queryAsyncJobResult_createvolumejob.json
Fri Jun 8 21:53:52 2012
@@ -0,0 +1 @@
+{ "queryasyncjobresultresponse" :
{"accountid":"be7d76b3-8823-49c0-86e1-29efd9ea1eb0","userid":"a8bd3087-edc1-4e94-8470-6830404b7292","cmd":"com.cloud.api.commands.CreateVolumeCmd","jobstatus":1,"jobprocstatus":0,"jobresultcode":0,"jobresulttype":"object","jobresult":{"volume":{"id":"60338035-92fb-4d27-98d4-b60ad4b38b87","name":"vol-0","zoneid":"58624957-a150-46a3-acbf-4088776161e5","zonename":"EQ-AMS2-Z01","type":"DATADISK","size":10737418240,"created":"2012-06-05T08:47:54+0200","state":"Allocated","account":"admin","domainid":"bfc35f83-8589-4e93-9150-d57e8479f772","domain":"ROOT","storagetype":"shared","hypervisor":"None","diskofferingid":"6345e3b7-227e-4209-8f8c-1f94219696e6","diskofferingname":"Disk
offering","diskofferingdisplaytext":"Disk offering display
name","storage":"none","destroyed":false,"isextractable":false}},"created":"2012-06-05T08:47:54+0200","jobid":"35416f6d-1b5b-4ceb-a7d4-aab0deede71b"}
}
Modified: libcloud/trunk/test/compute/test_cloudstack.py
URL:
http://svn.apache.org/viewvc/libcloud/trunk/test/compute/test_cloudstack.py?rev=1348260&r1=1348259&r2=1348260&view=diff
==============================================================================
--- libcloud/trunk/test/compute/test_cloudstack.py (original)
+++ libcloud/trunk/test/compute/test_cloudstack.py Fri Jun 8 21:53:52 2012
@@ -16,7 +16,7 @@ except AttributeError:
parse_qsl = cgi.parse_qsl
from libcloud.compute.drivers.cloudstack import CloudStackNodeDriver
-from libcloud.compute.types import DeploymentError
+from libcloud.compute.types import DeploymentError, LibcloudError
from test import MockHttpTestCase
from test.compute import TestCaseMixin
@@ -64,6 +64,61 @@ class CloudStackNodeDriverTest(unittest.
images = self.driver.list_images()
self.assertEquals(0, len(images))
+ def test_ex_list_disk_offerings(self):
+ diskOfferings = self.driver.ex_list_disk_offerings()
+ self.assertEquals(1, len(diskOfferings))
+
+ diskOffering, = diskOfferings
+
+ self.assertEquals('Disk offer 1', diskOffering.name)
+ self.assertEquals(10, diskOffering.size)
+
+ def test_ex_create_volume(self):
+ volumeName = 'vol-0'
+ location = self.driver.list_locations()[0]
+
+ volume = self.driver.ex_create_volume(
+ volumeName, location, size=10)
+
+ self.assertEquals(volumeName, volume.name)
+
+ def test_ex_create_volume_no_noncustomized_offering_with_size(self):
+ """If the sizes of disk offerings are not configurable and there
+ are no disk offerings with the requested size, an exception should
+ be thrown."""
+
+ location = self.driver.list_locations()[0]
+
+ self.assertRaises(
+ LibcloudError,
+ self.driver.ex_create_volume,
+ 'vol-0', location, 11)
+
+ def test_ex_create_volume_with_custom_disk_size_offering(self):
+
+ CloudStackMockHttp.fixture_tag = 'withcustomdisksize'
+
+ volumeName = 'vol-0'
+ location = self.driver.list_locations()[0]
+
+ volume = self.driver.ex_create_volume(
+ volumeName, location, size=11)
+
+ self.assertEquals(volumeName, volume.name)
+
+ def test_ex_attach_volume(self):
+ node = self.driver.list_nodes()[0]
+ volumeName = 'vol-0'
+ location = self.driver.list_locations()[0]
+
+ volume = self.driver.ex_create_volume(
+ volumeName, location, 10)
+
+ attachReturnVal = self.driver.ex_attach_volume(volume, node)
+
+ self.assertTrue(attachReturnVal)
+
+
class CloudStackMockHttp(MockHttpTestCase):
fixtures = ComputeFileFixtures('cloudstack')
fixture_tag = 'default'