Author: tomaz
Date: Mon Aug 13 03:28:21 2012
New Revision: 1372253
URL: http://svn.apache.org/viewvc?rev=1372253&view=rev
Log:
Add capacity information to Vdc objects and implement power operations.
Contributed by Michael Galet, part of LIBCLOUD-239.
Added:
libcloud/trunk/libcloud/test/compute/fixtures/vcloud_1_5/api_vApp_vapp_8c57a5b6_e61b_48ca_8a78_3b70ee65ef6a_power_action_all.xml
Modified:
libcloud/trunk/CHANGES
libcloud/trunk/libcloud/compute/drivers/vcloud.py
libcloud/trunk/libcloud/test/compute/fixtures/vcloud_1_5/api_vdc_3d9ae28c_1de9_4307_8107_9356ff8ba6d0.xml
libcloud/trunk/libcloud/test/compute/test_vcloud.py
Modified: libcloud/trunk/CHANGES
URL:
http://svn.apache.org/viewvc/libcloud/trunk/CHANGES?rev=1372253&r1=1372252&r2=1372253&view=diff
==============================================================================
--- libcloud/trunk/CHANGES (original)
+++ libcloud/trunk/CHANGES Mon Aug 13 03:28:21 2012
@@ -7,6 +7,10 @@ Changes with Apache Libcloud in developm
- Add new Rackspace Nova driver for Chicago (ORD) location ; LIBCLOUD-234
[Brian McDaniel]
+ - Add capacity information to Vdc objects and implement power operations. ;
+ LIBCLOUD-239
+ [Michal Galet]
+
*) Storage
- Add the following new methods to the CloudFiles driver:
Modified: libcloud/trunk/libcloud/compute/drivers/vcloud.py
URL:
http://svn.apache.org/viewvc/libcloud/trunk/libcloud/compute/drivers/vcloud.py?rev=1372253&r1=1372252&r2=1372253&view=diff
==============================================================================
--- libcloud/trunk/libcloud/compute/drivers/vcloud.py (original)
+++ libcloud/trunk/libcloud/compute/drivers/vcloud.py Mon Aug 13 03:28:21 2012
@@ -74,16 +74,32 @@ def get_url_path(url):
class Vdc:
"""Virtual datacenter (vDC) representation"""
- def __init__(self, id, name, driver):
+ def __init__(self, id, name, driver, allocation_model=None, cpu=None,
memory=None, storage=None):
self.id = id
self.name = name
self.driver = driver
+ self.allocation_model = allocation_model
+ self.cpu = cpu
+ self.memory = memory
+ self.storage = storage
def __repr__(self):
return (('<Vdc: id=%s, name=%s, driver=%s ...>')
% (self.id, self.name, self.driver.name))
+class Capacity:
+ """Represents CPU, Memory or Storage capacity of vDC."""
+ def __init__(self, limit, used, units):
+ self.limit = limit
+ self.used = used
+ self.units = units
+
+ def __repr__(self):
+ return (('<Capacity: limit=%s, used=%s, units=%s>')
+ % (self.limit, self.used, self.units))
+
+
class InstantiateVAppXML(object):
def __init__(self, name, template, net_href, cpus, memory,
password=None, row=None, group=None):
@@ -338,12 +354,17 @@ class VCloudNodeDriver(NodeDriver):
self.connection.check_org() # make sure the org is set. #
pylint: disable-msg=E1101
res = self.connection.request(self.org)
self._vdcs = [
- Vdc(i.get('href'), i.get('name'), self)
+ self._to_vdc(
+ self.connection.request(get_url_path(i.get('href'))).object
+ )
for i in res.object.findall(fixxpath(res.object, "Link"))
if i.get('type') == 'application/vnd.vmware.vcloud.vdc+xml'
]
return self._vdcs
+ def _to_vdc(self, vdc_elm):
+ return Vdc(vdc_elm.get('href'), vdc_elm.get('name'), self)
+
def _get_vdc(self, vdc_name):
vdc = None
if not vdc_name:
@@ -442,8 +463,8 @@ class VCloudNodeDriver(NodeDriver):
raise Exception("Canceled status returned by task %s."
% task_href)
if (time.time() - start_time >= timeout):
- raise Exception("Timeout while waiting for task %s."
- % task_href)
+ raise Exception("Timeout (%s sec) while waiting for task %s."
+ % (timeout, task_href))
time.sleep(5)
res = self.connection.request(get_url_path(task_href))
status = res.object.get('status')
@@ -482,8 +503,25 @@ class VCloudNodeDriver(NodeDriver):
return res.status in [httplib.ACCEPTED, httplib.NO_CONTENT]
def list_nodes(self):
+ return self.ex_list_nodes()
+
+ def ex_list_nodes(self, vdcs=None):
+ """
+ List all nodes across all vDCs. Using 'vdcs' you can specify which vDCs
+ should be queried.
+
+ @param vdcs: None, vDC or a list of vDCs to query. If None all vDCs
+ will be queried.
+ @type vdcs: L{Vdc}
+
+ @rtype: C{list} of L{Node} objects
+ """
+ if not vdcs:
+ vdcs = self.vdcs
+ if not isinstance(vdcs, (list, tuple)):
+ vdcs = [vdcs]
nodes = []
- for vdc in self.vdcs:
+ for vdc in vdcs:
res = self.connection.request(get_url_path(vdc.id))
elms = res.object.findall(fixxpath(
res.object, "ResourceEntities/ResourceEntity")
@@ -577,10 +615,10 @@ class VCloudNodeDriver(NodeDriver):
res = self._get_catalogitem(cat_item)
res_ents = res.findall(fixxpath(res, 'Entity'))
images += [
- self._to_image(i)
- for i in res_ents
- if i.get('type') ==
- 'application/vnd.vmware.vcloud.vAppTemplate+xml'
+ self._to_image(i)
+ for i in res_ents
+ if i.get('type') ==
+ 'application/vnd.vmware.vcloud.vAppTemplate+xml'
]
def idfun(image):
@@ -953,6 +991,62 @@ class VCloud_1_5_NodeDriver(VCloudNodeDr
res = self.connection.request(get_url_path(node.id))
return self._to_node(res.object)
+ def ex_power_off_node(self, node):
+ """
+ Powers on all VMs under specified node. VMs need to be This operation
+ is allowed only when the vApp/VM is powered on.
+
+ @param node: The node to be powered off
+ @type node: L{Node}
+
+ @rtype: L{Node}
+ """
+ return self._perform_power_operation(node, 'powerOff')
+
+ def ex_power_on_node(self, node):
+ """
+ Powers on all VMs under specified node. This operation is allowed
+ only when the vApp/VM is powered off or suspended.
+
+ @param node: The node to be powered on
+ @type node: L{Node}
+
+ @rtype: L{Node}
+ """
+ return self._perform_power_operation(node, 'powerOn')
+
+ def ex_shutdown_node(self, node):
+ """
+ Shutdowns all VMs under specified node. This operation is allowed only
+ when the vApp/VM is powered on.
+
+ @param node: The node to be shut down
+ @type node: L{Node}
+
+ @rtype: L{Node}
+ """
+ return self._perform_power_operation(node, 'shutdown')
+
+ def ex_suspend_node(self, node):
+ """
+ Suspends all VMs under specified node. This operation is allowed only
+ when the vApp/VM is powered on.
+
+ @param node: The node to be suspended
+ @type node: L{Node}
+
+ @rtype: L{Node}
+ """
+ return self._perform_power_operation(node, 'suspend')
+
+ def _perform_power_operation(self, node, operation):
+ res = self.connection.request(
+ '%s/power/action/%s' % (get_url_path(node.id), operation),
+ method='POST')
+ self._wait_for_task_completion(res.object.get('href'))
+ res = self.connection.request(get_url_path(node.id))
+ return self._to_node(res.object)
+
def create_node(self, **kwargs):
"""Creates and returns node. If the source image is:
- vApp template - a new vApp is instantiated from template
@@ -1529,11 +1623,38 @@ class VCloud_1_5_NodeDriver(VCloudNodeDr
public_ips.extend(vm['public_ips'])
private_ips.extend(vm['private_ips'])
+ # Find vDC
+ vdc_id = next(link.get('href') for link in
node_elm.findall(fixxpath(node_elm, 'Link'))
+ if link.get('type') == 'application/vnd.vmware.vcloud.vdc+xml')
+ vdc = next(vdc for vdc in self.vdcs if vdc.id == vdc_id)
+
node = Node(id=node_elm.get('href'),
name=node_elm.get('name'),
state=self.NODE_STATE_MAP[node_elm.get('status')],
public_ips=public_ips,
private_ips=private_ips,
driver=self.connection.driver,
- extra={'vms': vms})
+ extra={'vdc': vdc.name, 'vms': vms})
return node
+
+ def _to_vdc(self, vdc_elm):
+
+ def get_capacity_values(capacity_elm):
+ if capacity_elm is None:
+ return None
+ limit = int(capacity_elm.findtext(fixxpath(capacity_elm, 'Limit')))
+ used = int(capacity_elm.findtext(fixxpath(capacity_elm, 'Used')))
+ units = capacity_elm.findtext(fixxpath(capacity_elm, 'Units'))
+ return Capacity(limit, used, units)
+
+ cpu = get_capacity_values(vdc_elm.find(fixxpath(vdc_elm,
'ComputeCapacity/Cpu')))
+ memory = get_capacity_values(vdc_elm.find(fixxpath(vdc_elm,
'ComputeCapacity/Memory')))
+ storage = get_capacity_values(vdc_elm.find(fixxpath(vdc_elm,
'StorageCapacity')))
+
+ return Vdc(id=vdc_elm.get('href'),
+ name=vdc_elm.get('name'),
+ driver=self,
+ allocation_model=vdc_elm.findtext(fixxpath(vdc_elm,
'AllocationModel')),
+ cpu=cpu,
+ memory=memory,
+ storage=storage)
Added:
libcloud/trunk/libcloud/test/compute/fixtures/vcloud_1_5/api_vApp_vapp_8c57a5b6_e61b_48ca_8a78_3b70ee65ef6a_power_action_all.xml
URL:
http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/fixtures/vcloud_1_5/api_vApp_vapp_8c57a5b6_e61b_48ca_8a78_3b70ee65ef6a_power_action_all.xml?rev=1372253&view=auto
==============================================================================
---
libcloud/trunk/libcloud/test/compute/fixtures/vcloud_1_5/api_vApp_vapp_8c57a5b6_e61b_48ca_8a78_3b70ee65ef6a_power_action_all.xml
(added)
+++
libcloud/trunk/libcloud/test/compute/fixtures/vcloud_1_5/api_vApp_vapp_8c57a5b6_e61b_48ca_8a78_3b70ee65ef6a_power_action_all.xml
Mon Aug 13 03:28:21 2012
@@ -0,0 +1,10 @@
+<Task status="running" startTime="2011-12-20T15:39:53.270-05:00"
operationName="[my power operation]"
+ operation="Power On/Power Off/Reset/Suspend Virtual Application
(0d647cbf-867e-442d-8d2d-d0c2d235fbdf)"
expiryTime="2012-03-19T15:39:53.270-04:00"
+ name="task" id="urn:vcloud:task:b034df55-fe81-4798-bc81-1f0fd0ead450"
+ type="application/vnd.vmware.vcloud.task+xml"
+ href="https://vm-vcloud/api/task/b034df55-fe81-4798-bc81-1f0fd0ead450"
xsi:schemaLocation="http://www.vmware.com/vcloud/v1.5
http://65.41.64.27/api/v1.5/schema/master.xsd"
xmlns="http://www.vmware.com/vcloud/v1.5"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <Link rel="task:cancel"
href="https://vm-vcloud/api/task/b034df55-fe81-4798-bc81-1f0fd0ead450/action/cancel"/>
+ <Owner type="application/vnd.vmware.vcloud.vApp+xml" name=""
href="https://vm-vcloud/api/vApp/vapp-0d647cbf-867e-442d-8d2d-d0c2d235fbdf"/>
+ <User type="application/vnd.vmware.admin.user+xml" name="labmanapi"
href="https://vm-vcloud/api/admin/user/46f62cc3-65e0-4417-967a-a538ec6caea3"/>
+ <Organization type="application/vnd.vmware.vcloud.org+xml" name="MyOrg"
href="https://vm-vcloud/api/org/96726c78-4ae3-402f-b08b-7a78c6903d2a"/>
+</Task>
\ No newline at end of file
Modified:
libcloud/trunk/libcloud/test/compute/fixtures/vcloud_1_5/api_vdc_3d9ae28c_1de9_4307_8107_9356ff8ba6d0.xml
URL:
http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/fixtures/vcloud_1_5/api_vdc_3d9ae28c_1de9_4307_8107_9356ff8ba6d0.xml?rev=1372253&r1=1372252&r2=1372253&view=diff
==============================================================================
---
libcloud/trunk/libcloud/test/compute/fixtures/vcloud_1_5/api_vdc_3d9ae28c_1de9_4307_8107_9356ff8ba6d0.xml
(original)
+++
libcloud/trunk/libcloud/test/compute/fixtures/vcloud_1_5/api_vdc_3d9ae28c_1de9_4307_8107_9356ff8ba6d0.xml
Mon Aug 13 03:28:21 2012
@@ -1,4 +1,4 @@
-<Vdc status="1" name="MyOrg"
id="urn:vcloud:vdc:3d9ae28c-1de9-4307-8107-9356ff8ba6d0"
type="application/vnd.vmware.vcloud.vdc+xml"
href="https://vm-vcloud/api/vdc/3d9ae28c-1de9-4307-8107-9356ff8ba6d0"
xsi:schemaLocation="http://www.vmware.com/vcloud/v1.5
http://65.41.64.27/api/v1.5/schema/master.xsd"
xmlns="http://www.vmware.com/vcloud/v1.5"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+<Vdc status="1" name="MyVdc"
id="urn:vcloud:vdc:3d9ae28c-1de9-4307-8107-9356ff8ba6d0"
type="application/vnd.vmware.vcloud.vdc+xml"
href="https://vm-vcloud/api/vdc/3d9ae28c-1de9-4307-8107-9356ff8ba6d0"
xsi:schemaLocation="http://www.vmware.com/vcloud/v1.5
http://65.41.64.27/api/v1.5/schema/master.xsd"
xmlns="http://www.vmware.com/vcloud/v1.5"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Link rel="up" type="application/vnd.vmware.vcloud.org+xml"
href="https://vm-vcloud/api/org/96726c78-4ae3-402f-b08b-7a78c6903d2a"/>
<Link rel="down" type="application/vnd.vmware.vcloud.metadata+xml"
href="https://vm-vcloud/api/vdc/3d9ae28c-1de9-4307-8107-9356ff8ba6d0/metadata"/>
<Link rel="add"
type="application/vnd.vmware.vcloud.uploadVAppTemplateParams+xml"
href="https://vm-vcloud/api/vdc/3d9ae28c-1de9-4307-8107-9356ff8ba6d0/action/uploadVAppTemplate"/>
@@ -9,27 +9,27 @@
<Link rel="add" type="application/vnd.vmware.vcloud.cloneMediaParams+xml"
href="https://vm-vcloud/api/vdc/3d9ae28c-1de9-4307-8107-9356ff8ba6d0/action/cloneMedia"/>
<Link rel="add" type="application/vnd.vmware.vcloud.captureVAppParams+xml"
href="https://vm-vcloud/api/vdc/3d9ae28c-1de9-4307-8107-9356ff8ba6d0/action/captureVApp"/>
<Link rel="add" type="application/vnd.vmware.vcloud.composeVAppParams+xml"
href="https://vm-vcloud/api/vdc/3d9ae28c-1de9-4307-8107-9356ff8ba6d0/action/composeVApp"/>
- <AllocationModel>AllocationVApp</AllocationModel>
+ <AllocationModel>AllocationPool</AllocationModel>
<StorageCapacity>
<Units>MB</Units>
- <Allocated>0</Allocated>
- <Limit>0</Limit>
- <Used>126976</Used>
+ <Allocated>5120000</Allocated>
+ <Limit>5120000</Limit>
+ <Used>1984512</Used>
<Overhead>0</Overhead>
</StorageCapacity>
<ComputeCapacity>
<Cpu>
<Units>MHz</Units>
- <Allocated>0</Allocated>
- <Limit>0</Limit>
- <Used>6000</Used>
+ <Allocated>130000</Allocated>
+ <Limit>160000</Limit>
+ <Used>0</Used>
<Overhead>0</Overhead>
</Cpu>
<Memory>
<Units>MB</Units>
- <Allocated>0</Allocated>
- <Limit>0</Limit>
- <Used>4255</Used>
+ <Allocated>527360</Allocated>
+ <Limit>527360</Limit>
+ <Used>130752</Used>
<Overhead>0</Overhead>
</Memory>
</ComputeCapacity>
Modified: libcloud/trunk/libcloud/test/compute/test_vcloud.py
URL:
http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/test_vcloud.py?rev=1372253&r1=1372252&r2=1372253&view=diff
==============================================================================
--- libcloud/trunk/libcloud/test/compute/test_vcloud.py (original)
+++ libcloud/trunk/libcloud/test/compute/test_vcloud.py Mon Aug 13 03:28:21 2012
@@ -132,7 +132,8 @@ class VCloud_1_5_Tests(unittest.TestCase
self.assertEqual(node.state, NodeState.RUNNING)
self.assertEqual(node.public_ips, ['65.41.67.2'])
self.assertEqual(node.private_ips, ['65.41.67.2'])
- self.assertEqual(node.extra, {'vms': [{
+ self.assertEqual(node.extra, {'vdc': 'MyVdc',
+ 'vms': [{
'id':
'https://vm-vcloud/api/vApp/vm-dd75d1d3-5b7b-48f0-aff3-69622ab7e045',
'name': 'testVm',
'state': NodeState.RUNNING,
@@ -145,7 +146,8 @@ class VCloud_1_5_Tests(unittest.TestCase
self.assertEqual(node.state, NodeState.RUNNING)
self.assertEqual(node.public_ips, ['192.168.0.103'])
self.assertEqual(node.private_ips, ['192.168.0.100'])
- self.assertEqual(node.extra, {'vms': [{
+ self.assertEqual(node.extra, {'vdc': 'MyVdc',
+ 'vms': [{
'id':
'https://vm-vcloud/api/vApp/vm-dd75d1d3-5b7b-48f0-aff3-69622ab7e046',
'name': 'testVm2',
'state': NodeState.RUNNING,
@@ -218,6 +220,30 @@ class VCloud_1_5_Tests(unittest.TestCase
def test_ex_set_vm_memory(self):
self.driver.ex_set_vm_memory('https://test/api/vApp/vm-test', 1024)
+ def test_vdcs(self):
+ vdcs = self.driver.vdcs
+ self.assertEqual(len(vdcs), 1)
+ self.assertEqual(vdcs[0].id,
'https://vm-vcloud/api/vdc/3d9ae28c-1de9-4307-8107-9356ff8ba6d0')
+ self.assertEqual(vdcs[0].name, 'MyVdc')
+ self.assertEqual(vdcs[0].allocation_model, 'AllocationPool')
+ self.assertEqual(vdcs[0].storage.limit, 5120000)
+ self.assertEqual(vdcs[0].storage.used, 1984512)
+ self.assertEqual(vdcs[0].storage.units, 'MB')
+ self.assertEqual(vdcs[0].cpu.limit, 160000)
+ self.assertEqual(vdcs[0].cpu.used, 0)
+ self.assertEqual(vdcs[0].cpu.units, 'MHz')
+ self.assertEqual(vdcs[0].memory.limit, 527360)
+ self.assertEqual(vdcs[0].memory.used, 130752)
+ self.assertEqual(vdcs[0].memory.units, 'MB')
+
+ def test_ex_list_nodes(self):
+ self.assertEqual(len(self.driver.ex_list_nodes()),
len(self.driver.list_nodes()))
+
+ def test_ex_power_off(self):
+ node =
Node('https://vm-vcloud/api/vApp/vapp-8c57a5b6-e61b-48ca-8a78-3b70ee65ef6b',
'testNode', NodeState.RUNNING, [], [], self.driver)
+ self.driver.ex_power_off_node(node)
+
+
class TerremarkMockHttp(MockHttp):
@@ -316,8 +342,7 @@ class VCloud_1_5_MockHttp(MockHttp):
return httplib.ACCEPTED, body, headers,
httplib.responses[httplib.ACCEPTED]
def
_api_vApp_vapp_8c57a5b6_e61b_48ca_8a78_3b70ee65ef6a_power_action_powerOn(self,
method, url, body, headers):
- body =
self.fixtures.load('api_vApp_vapp_8c57a5b6_e61b_48ca_8a78_3b70ee65ef6a_power_action_powerOn.xml')
- return httplib.ACCEPTED, body, headers,
httplib.responses[httplib.ACCEPTED]
+ return
self._api_vApp_vapp_8c57a5b6_e61b_48ca_8a78_3b70ee65ef6b_power_action_all(method,
url, body, headers)
# Clone
def _api_vdc_3d9ae28c_1de9_4307_8107_9356ff8ba6d0_action_cloneVApp(self,
method, url, body, headers):
@@ -356,8 +381,7 @@ class VCloud_1_5_MockHttp(MockHttp):
return status, body, headers, httplib.responses[status]
def
_api_vApp_vapp_8c57a5b6_e61b_48ca_8a78_3b70ee65ef6a_power_action_reset(self,
method, url, body, headers):
- body =
self.fixtures.load('api_vApp_vapp_8c57a5b6_e61b_48ca_8a78_3b70ee65ef6a_power_action_reset.xml')
- return httplib.ACCEPTED, body, headers,
httplib.responses[httplib.ACCEPTED]
+ return
self._api_vApp_vapp_8c57a5b6_e61b_48ca_8a78_3b70ee65ef6b_power_action_all(method,
url, body, headers)
def _api_task_b034df55_fe81_4798_bc81_1f0fd0ead450(self, method, url,
body, headers):
body =
self.fixtures.load('api_task_b034df55_fe81_4798_bc81_1f0fd0ead450.xml')
@@ -432,5 +456,13 @@ class VCloud_1_5_MockHttp(MockHttp):
status = httplib.ACCEPTED
return status, body, headers, httplib.responses[status]
+ def
_api_vApp_vapp_8c57a5b6_e61b_48ca_8a78_3b70ee65ef6b_power_action_powerOff(self,
method, url, body, headers):
+ return
self._api_vApp_vapp_8c57a5b6_e61b_48ca_8a78_3b70ee65ef6b_power_action_all(method,
url, body, headers)
+
+ def
_api_vApp_vapp_8c57a5b6_e61b_48ca_8a78_3b70ee65ef6b_power_action_all(self,
method, url, body, headers):
+ assert method == 'POST'
+ body =
self.fixtures.load('api_vApp_vapp_8c57a5b6_e61b_48ca_8a78_3b70ee65ef6a_power_action_all.xml')
+ return httplib.ACCEPTED, body, headers,
httplib.responses[httplib.ACCEPTED]
+
if __name__ == '__main__':
sys.exit(unittest.main())