Author: tomaz
Date: Sun Oct 23 12:03:25 2011
New Revision: 1187872
URL: http://svn.apache.org/viewvc?rev=1187872&view=rev
Log:
OpenStack and Opsource driver style and code cleanup. No functional changes.
Contributed by Hutson Betts <hut606 at gmail dot com> part of LIBCLOUD-123.
Modified:
libcloud/trunk/libcloud/compute/drivers/openstack.py
libcloud/trunk/libcloud/compute/drivers/opsource.py
Modified: libcloud/trunk/libcloud/compute/drivers/openstack.py
URL:
http://svn.apache.org/viewvc/libcloud/trunk/libcloud/compute/drivers/openstack.py?rev=1187872&r1=1187871&r2=1187872&view=diff
==============================================================================
--- libcloud/trunk/libcloud/compute/drivers/openstack.py (original)
+++ libcloud/trunk/libcloud/compute/drivers/openstack.py Sun Oct 23 12:03:25
2011
@@ -23,19 +23,20 @@ except ImportError:
import os
-import base64
-import httplib
import warnings
+import httplib
+import base64
from xml.etree import ElementTree as ET
-from libcloud.pricing import get_size_price
-from libcloud.common.base import Response
+from libcloud.common.openstack import OpenStackBaseConnection
from libcloud.common.types import MalformedResponseError
from libcloud.compute.types import NodeState, Provider
-from libcloud.compute.base import NodeDriver, Node
from libcloud.compute.base import NodeSize, NodeImage
-from libcloud.common.openstack import OpenStackBaseConnection
+from libcloud.compute.base import NodeDriver, Node
+from libcloud.pricing import get_size_price
+from libcloud.common.base import Response
+from libcloud.utils import findall
__all__ = [
'OpenStack_1_0_Response',
@@ -47,32 +48,14 @@ __all__ = [
'OpenStack_1_1_Connection',
'OpenStack_1_1_NodeDriver',
'OpenStackNodeDriver'
- ]
-
+ ]
ATOM_NAMESPACE = "http://www.w3.org/2005/Atom"
-OPENSTACK_NODE_STATE_MAP = {'BUILD': NodeState.PENDING,
- 'REBUILD': NodeState.PENDING,
- 'ACTIVE': NodeState.RUNNING,
- 'SUSPENDED': NodeState.TERMINATED,
- 'QUEUE_RESIZE': NodeState.PENDING,
- 'PREP_RESIZE': NodeState.PENDING,
- 'VERIFY_RESIZE': NodeState.RUNNING,
- 'PASSWORD': NodeState.PENDING,
- 'RESCUE': NodeState.PENDING,
- 'REBUILD': NodeState.PENDING,
- 'REBOOT': NodeState.REBOOTING,
- 'HARD_REBOOT': NodeState.REBOOTING,
- 'SHARE_IP': NodeState.PENDING,
- 'SHARE_IP_NO_CONFIG': NodeState.PENDING,
- 'DELETE_IP': NodeState.PENDING,
- 'UNKNOWN': NodeState.UNKNOWN}
-
DEFAULT_API_VERSION = '1.1'
-class OpenStack_Response(Response):
+class OpenStackResponse(Response):
node_driver = None
@@ -147,11 +130,32 @@ class OpenStackComputeConnection(OpenSta
return super(OpenStackComputeConnection, self).request(
action=action,
params=params, data=data,
- method=method, headers=headers
- )
+ method=method, headers=headers)
class OpenStackNodeDriver(NodeDriver):
+ """
+ Base OpenStack node driver. Should not be used directly.
+ """
+
+ NODE_STATE_MAP = {
+ 'BUILD': NodeState.PENDING,
+ 'REBUILD': NodeState.PENDING,
+ 'ACTIVE': NodeState.RUNNING,
+ 'SUSPENDED': NodeState.TERMINATED,
+ 'QUEUE_RESIZE': NodeState.PENDING,
+ 'PREP_RESIZE': NodeState.PENDING,
+ 'VERIFY_RESIZE': NodeState.RUNNING,
+ 'PASSWORD': NodeState.PENDING,
+ 'RESCUE': NodeState.PENDING,
+ 'REBUILD': NodeState.PENDING,
+ 'REBOOT': NodeState.REBOOTING,
+ 'HARD_REBOOT': NodeState.REBOOTING,
+ 'SHARE_IP': NodeState.PENDING,
+ 'SHARE_IP_NO_CONFIG': NodeState.PENDING,
+ 'DELETE_IP': NodeState.PENDING,
+ 'UNKNOWN': NodeState.UNKNOWN
+ }
def __new__(cls, key, secret=None, secure=True, host=None, port=None,
api_version=DEFAULT_API_VERSION, **kwargs):
@@ -163,31 +167,43 @@ class OpenStackNodeDriver(NodeDriver):
else:
raise NotImplementedError(
"No OpenStackNodeDriver found for API version %s" %
- (api_version)
- )
+ (api_version))
return super(OpenStackNodeDriver, cls).__new__(cls)
- def _ex_connection_class_kwargs(self):
- rv = {}
- if self._ex_force_base_url:
- rv['ex_force_base_url'] = self._ex_force_base_url
- if self._ex_force_auth_url:
- rv['ex_force_auth_url'] = self._ex_force_auth_url
- if self._ex_force_auth_version:
- rv['ex_force_auth_version'] = self._ex_force_auth_version
- return rv
+ def destroy_node(self, node):
+ uri = '/servers/%s' % (node.id)
+ resp = self.connection.request(uri, method='DELETE')
+ # The OpenStack and Rackspace documentation both say this API will
+ # return a 204, but in-fact, everyone everywhere agrees it actually
+ # returns a 202, so we are going to accept either, and someday,
+ # someone will fix either the implementation or the documentation to
+ # agree.
+ return resp.status in (httplib.NO_CONTENT, httplib.ACCEPTED)
+
+ def reboot_node(self, node):
+ return self._reboot_node(node, reboot_type='HARD')
def list_nodes(self):
return self._to_nodes(self.connection.request('/servers/detail')
.object)
+ def list_images(self, location=None, ex_only_active=True):
+ return self._to_images(self.connection.request('/images/detail')
+ .object, ex_only_active)
+
def list_sizes(self, location=None):
return self._to_sizes(self.connection.request('/flavors/detail')
.object)
- def list_images(self, location=None, ex_only_active=True):
- return self._to_images(self.connection.request('/images/detail')
- .object, ex_only_active)
+ def _ex_connection_class_kwargs(self):
+ rv = {}
+ if self._ex_force_base_url:
+ rv['ex_force_base_url'] = self._ex_force_base_url
+ if self._ex_force_auth_url:
+ rv['ex_force_auth_url'] = self._ex_force_auth_url
+ if self._ex_force_auth_version:
+ rv['ex_force_auth_version'] = self._ex_force_auth_version
+ return rv
def ex_get_node_details(self, node_id):
# @TODO: Remove this if in 0.6
@@ -201,27 +217,14 @@ class OpenStackNodeDriver(NodeDriver):
return self._to_node_from_obj(resp.object)
- def destroy_node(self, node):
- uri = '/servers/%s' % (node.id)
- resp = self.connection.request(uri, method='DELETE')
- # The OpenStack and Rackspace documentation both say this API will
- # return a 204, but in-fact, everyone everywhere agrees it actually
- # returns a 202, so we are going to accept either, and someday,
- # someone will fix either the implementation or the documentation to
- # agree.
- return resp.status in (httplib.NO_CONTENT, httplib.ACCEPTED)
-
def ex_soft_reboot_node(self, node):
return self._reboot_node(node, reboot_type='SOFT')
def ex_hard_reboot_node(self, node):
return self._reboot_node(node, reboot_type='HARD')
- def reboot_node(self, node):
- return self._reboot_node(node, reboot_type='HARD')
-
-class OpenStack_1_0_Response(OpenStack_Response):
+class OpenStack_1_0_Response(OpenStackResponse):
def __init__(self, *args, **kwargs):
# done because of a circular reference from
@@ -255,8 +258,6 @@ class OpenStack_1_0_NodeDriver(OpenStack
features = {"create_node": ["generates_password"]}
- NODE_STATE_MAP = OPENSTACK_NODE_STATE_MAP
-
def __init__(self, *args, **kwargs):
self._ex_force_base_url = kwargs.pop('ex_force_base_url', None)
self._ex_force_auth_url = kwargs.pop('ex_force_auth_url', None)
@@ -266,6 +267,25 @@ class OpenStack_1_0_NodeDriver(OpenStack
self.XML_NAMESPACE = self.connectionCls.XML_NAMESPACE
super(OpenStack_1_0_NodeDriver, self).__init__(*args, **kwargs)
+ def _to_images(self, object, ex_only_active):
+ images = []
+ for image in findall(object, 'image', self.XML_NAMESPACE):
+ if ex_only_active and image.get('status') != 'ACTIVE':
+ continue
+ images.append(self._to_image(image))
+
+ return images
+
+ def _to_image(self, element):
+ return NodeImage(id=element.get('id'),
+ name=element.get('name'),
+ driver=self.connection.driver,
+ extra={'updated': element.get('updated'),
+ 'created': element.get('created'),
+ 'status': element.get('status'),
+ 'serverId': element.get('serverId'),
+ 'progress': element.get('progress')})
+
def _change_password_or_name(self, node, name=None, password=None):
uri = '/servers/%s' % (node.id)
@@ -283,32 +303,14 @@ class OpenStack_1_0_NodeDriver(OpenStack
resp = self.connection.request(
uri, method='PUT', data=ET.tostring(server_elm))
- if resp.status == 204 and password != None:
+ if resp.status == httplib.NO_CONTENT and password != None:
node.extra['password'] = password
- return resp.status == 204
-
- def ex_set_password(self, node, password):
- """
- Sets the Node's root password.
-
- This will reboot the instance to complete the operation.
-
- L{node.extra['password']} will be set to the new value if the
- operation was successful.
- """
- return self._change_password_or_name(node, password=password)
-
- def ex_set_server_name(self, node, name):
- """
- Sets the Node's name.
-
- This will reboot the instance to complete the operation.
- """
- return self._change_password_or_name(node, name=name)
+ return resp.status == httplib.NO_CONTENT
def create_node(self, **kwargs):
- """Create a new node
+ """
+ Create a new node
See L{NodeDriver.create_node} for more keyword args.
@keyword ex_metadata: Key/Value metadata to associate with a node
@@ -325,8 +327,7 @@ class OpenStack_1_0_NodeDriver(OpenStack
attributes = {'xmlns': self.XML_NAMESPACE,
'name': name,
'imageId': str(image.id),
- 'flavorId': str(size.id)
- }
+ 'flavorId': str(size.id)}
if 'ex_shared_ip_group' in kwargs:
# Deprecate this. Be explicit and call the variable
@@ -354,6 +355,25 @@ class OpenStack_1_0_NodeDriver(OpenStack
data=ET.tostring(server_elm))
return self._to_node(resp.object)
+ def ex_set_password(self, node, password):
+ """
+ Sets the Node's root password.
+
+ This will reboot the instance to complete the operation.
+
+ L{node.extra['password']} will be set to the new value if the
+ operation was successful.
+ """
+ return self._change_password_or_name(node, password=password)
+
+ def ex_set_server_name(self, node, name):
+ """
+ Sets the Node's name.
+
+ This will reboot the instance to complete the operation.
+ """
+ return self._change_password_or_name(node, name=name)
+
def ex_resize(self, node, size):
"""
Change an existing server flavor / scale the server up or down.
@@ -374,7 +394,7 @@ class OpenStack_1_0_NodeDriver(OpenStack
resp = self.connection.request("/servers/%s/action" % (node.id),
method='POST',
data=ET.tostring(elm))
- return resp.status == 202
+ return resp.status == httplib.ACCEPTED
def ex_confirm_resize(self, node):
"""
@@ -389,13 +409,13 @@ class OpenStack_1_0_NodeDriver(OpenStack
"""
elm = ET.Element(
'confirmResize',
- {'xmlns': self.XML_NAMESPACE}
+ {'xmlns': self.XML_NAMESPACE},
)
resp = self.connection.request("/servers/%s/action" % (node.id),
method='POST',
data=ET.tostring(elm))
- return resp.status == 204
+ return resp.status == httplib.NO_CONTENT
def ex_revert_resize(self, node):
"""
@@ -416,7 +436,7 @@ class OpenStack_1_0_NodeDriver(OpenStack
resp = self.connection.request("/servers/%s/action" % (node.id),
method='POST',
data=ET.tostring(elm))
- return resp.status == 204
+ return resp.status == httplib.NO_CONTENT
def ex_rebuild(self, node_id, image_id):
# @TODO: Remove those ifs in 0.6
@@ -432,10 +452,11 @@ class OpenStack_1_0_NodeDriver(OpenStack
'imageId': image_id,
}
)
+
resp = self.connection.request("/servers/%s/action" % node_id,
method='POST',
data=ET.tostring(elm))
- return resp.status == 202
+ return resp.status == httplib.ACCEPTED
def ex_create_ip_group(self, group_name, node_id=None):
# @TODO: Remove this if in 0.6
@@ -464,13 +485,14 @@ class OpenStack_1_0_NodeDriver(OpenStack
uri = '/shared_ip_groups/detail' if details else '/shared_ip_groups'
resp = self.connection.request(uri,
method='GET')
- groups = self._findall(resp.object, 'sharedIpGroup')
+ groups = findall(resp.object, 'sharedIpGroup',
+ self.XML_NAMESPACE)
return [self._to_shared_ip_group(el) for el in groups]
def ex_delete_ip_group(self, group_id):
uri = '/shared_ip_groups/%s' % group_id
resp = self.connection.request(uri, method='DELETE')
- return resp.status == 204
+ return resp.status == httplib.NO_CONTENT
def ex_share_ip(self, group_id, node_id, ip, configure_node=True):
# @TODO: Remove this if in 0.6
@@ -486,7 +508,7 @@ class OpenStack_1_0_NodeDriver(OpenStack
'shareIp',
{'xmlns': self.XML_NAMESPACE,
'sharedIpGroupId': group_id,
- 'configureServer': str_configure}
+ 'configureServer': str_configure},
)
uri = '/servers/%s/ips/public/%s' % (node_id, ip)
@@ -494,7 +516,7 @@ class OpenStack_1_0_NodeDriver(OpenStack
resp = self.connection.request(uri,
method='PUT',
data=ET.tostring(elm))
- return resp.status == 202
+ return resp.status == httplib.ACCEPTED
def ex_unshare_ip(self, node_id, ip):
# @TODO: Remove this if in 0.6
@@ -505,7 +527,7 @@ class OpenStack_1_0_NodeDriver(OpenStack
resp = self.connection.request(uri,
method='DELETE')
- return resp.status == 202
+ return resp.status == httplib.ACCEPTED
def ex_list_ip_addresses(self, node_id):
# @TODO: Remove this if in 0.6
@@ -543,7 +565,7 @@ class OpenStack_1_0_NodeDriver(OpenStack
def _reboot_node(self, node, reboot_type='SOFT'):
resp = self._node_action(node, ['reboot', ('type', reboot_type)])
- return resp.status == 202
+ return resp.status == httplib.ACCEPTED
def _node_action(self, node, body):
if isinstance(body, list):
@@ -555,19 +577,12 @@ class OpenStack_1_0_NodeDriver(OpenStack
return resp
def _to_nodes(self, object):
- node_elements = self._findall(object, 'server')
+ node_elements = findall(object, 'server', self.XML_NAMESPACE)
return [self._to_node(el) for el in node_elements]
- def _fixxpath(self, xpath):
- # ElementTree wants namespaces in its xpaths, so here we add them.
- return "/".join(["{%s}%s" % (self.XML_NAMESPACE, e) for e
- in xpath.split("/")])
-
- def _findall(self, element, xpath):
- return element.findall(self._fixxpath(xpath))
-
def _to_node_from_obj(self, obj):
- return self._to_node(self._findall(obj, 'server')[0])
+ return self._to_node(findall(obj, 'server',
+ self.XML_NAMESPACE)[0])
def _to_node(self, el):
def get_ips(el):
@@ -579,11 +594,12 @@ class OpenStack_1_0_NodeDriver(OpenStack
d[meta.get('key')] = meta.text
return d
- public_ip = get_ips(self._findall(el,
- 'addresses/public/ip'))
- private_ip = get_ips(self._findall(el,
- 'addresses/private/ip'))
- metadata = get_meta_dict(self._findall(el, 'metadata/meta'))
+ public_ip = get_ips(findall(el, 'addresses/public/ip',
+ self.XML_NAMESPACE))
+ private_ip = get_ips(findall(el, 'addresses/private/ip',
+ self.XML_NAMESPACE))
+ metadata = get_meta_dict(findall(el, 'metadata/meta',
+ self.XML_NAMESPACE))
n = Node(id=el.get('id'),
name=el.get('name'),
@@ -605,11 +621,11 @@ class OpenStack_1_0_NodeDriver(OpenStack
return n
def _to_sizes(self, object):
- elements = self._findall(object, 'flavor')
+ elements = findall(object, 'flavor', self.XML_NAMESPACE)
return [self._to_size(el) for el in elements]
def _to_size(self, el):
- s = NodeSize(id=el.get('id'),
+ return NodeSize(id=el.get('id'),
name=el.get('name'),
ram=int(el.get('ram')),
disk=int(el.get('disk')),
@@ -618,27 +634,6 @@ class OpenStack_1_0_NodeDriver(OpenStack
# Hardcoded
price=self._get_size_price(el.get('id')),
driver=self.connection.driver)
- return s
-
- def _to_images(self, object, ex_only_active):
- elements = self._findall(object, "image")
- rv = []
- for el in elements:
- if ex_only_active and el.get('status') != 'ACTIVE':
- continue
- rv.append(self._to_image(el))
- return rv
-
- def _to_image(self, el):
- i = NodeImage(id=el.get('id'),
- name=el.get('name'),
- driver=self.connection.driver,
- extra={'updated': el.get('updated'),
- 'created': el.get('created'),
- 'status': el.get('status'),
- 'serverId': el.get('serverId'),
- 'progress': el.get('progress')})
- return i
def ex_limits(self):
"""
@@ -661,9 +656,11 @@ class OpenStack_1_0_NodeDriver(OpenStack
return {el.get('name'): el.get('value')}
limits = self.connection.request("/limits").object
- rate = [_to_rate(el) for el in self._findall(limits, 'rate/limit')]
+ rate = [_to_rate(el) for el in findall(limits, 'rate/limit',
+ self.XML_NAMESPACE)]
absolute = {}
- for item in self._findall(limits, 'absolute/limit'):
+ for item in findall(limits, 'absolute/limit',
+ self.XML_NAMESPACE):
absolute.update(_to_absolute(item))
return {"rate": rate, "absolute": absolute}
@@ -681,8 +678,7 @@ class OpenStack_1_0_NodeDriver(OpenStack
'image',
{'xmlns': self.XML_NAMESPACE,
'name': name,
- 'serverId': node.id}
- )
+ 'serverId': node.id})
return self._to_image(self.connection.request("/images",
method="POST",
@@ -696,13 +692,14 @@ class OpenStack_1_0_NodeDriver(OpenStack
"""
uri = '/images/%s' % image.id
resp = self.connection.request(uri, method='DELETE')
- return resp.status == 204
+ return resp.status == httplib.NO_CONTENT
def _to_shared_ip_group(self, el):
- servers_el = self._findall(el, 'servers')
+ servers_el = findall(el, 'servers', self.XML_NAMESPACE)
if servers_el:
servers = [s.get('id')
- for s in self._findall(servers_el[0], 'server')]
+ for s in findall(servers_el[0], 'server',
+ self.XML_NAMESPACE)]
else:
servers = None
return OpenStack_1_0_SharedIpGroup(id=el.get('id'),
@@ -712,10 +709,11 @@ class OpenStack_1_0_NodeDriver(OpenStack
def _to_ip_addresses(self, el):
return OpenStack_1_0_NodeIpAddresses(
[ip.get('addr') for ip in
- self._findall(self._findall(el, 'public')[0], 'ip')],
+ findall(findall(el, 'public', self.XML_NAMESPACE)[0],
+ 'ip', self.XML_NAMESPACE)],
[ip.get('addr') for ip in
- self._findall(self._findall(el, 'private')[0], 'ip')]
- )
+ findall(findall(el, 'private', self.XML_NAMESPACE)[0],
+ 'ip', self.XML_NAMESPACE)])
def _get_size_price(self, size_id):
try:
@@ -747,7 +745,7 @@ class OpenStack_1_0_NodeIpAddresses(obje
self.private_addresses = private_addresses
-class OpenStack_1_1_Response(OpenStack_Response):
+class OpenStack_1_1_Response(OpenStackResponse):
def __init__(self, *args, **kwargs):
# done because of a circular reference from
@@ -777,8 +775,6 @@ class OpenStack_1_1_NodeDriver(OpenStack
features = {"create_node": ["generates_password"]}
- NODE_STATE_MAP = OPENSTACK_NODE_STATE_MAP
-
def __init__(self, *args, **kwargs):
self._ex_force_base_url = kwargs.pop('ex_force_base_url', None)
self._ex_force_auth_url = kwargs.pop('ex_force_auth_url', None)
@@ -788,6 +784,49 @@ class OpenStack_1_1_NodeDriver(OpenStack
None))
super(OpenStack_1_1_NodeDriver, self).__init__(*args, **kwargs)
+ def create_node(self, **kwargs):
+ """Create a new node
+
+ See L{NodeDriver.create_node} for more keyword args.
+ @keyword ex_metadata: Key/Value metadata to associate with a node
+ @type ex_metadata: C{dict}
+
+ @keyword ex_files: File Path => File contents to create on
+ the node
+ @type ex_files: C{dict}
+ """
+
+ server_params = self._create_args_to_params(None, kwargs)
+
+ resp = self.connection.request("/servers",
+ method='POST',
+ data={'server': server_params})
+
+ return self._to_node(resp.object['server'])
+
+ def _to_images(self, obj, ex_only_active):
+ images = []
+ for image in obj['images']:
+ if ex_only_active and image.get('status') != 'ACTIVE':
+ continue
+ images.append(self._to_image(image))
+
+ return images
+
+ def _to_image(self, api_image):
+ return NodeImage(
+ id=api_image['id'],
+ name=api_image['name'],
+ driver=self,
+ extra=dict(
+ updated=api_image['updated'],
+ created=api_image['created'],
+ status=api_image['status'],
+ progress=api_image.get('progress'),
+ metadata=api_image.get('metadata'),
+ )
+ )
+
def _to_nodes(self, obj):
servers = obj['servers']
return [self._to_node(server) for server in servers]
@@ -796,15 +835,6 @@ class OpenStack_1_1_NodeDriver(OpenStack
flavors = obj['flavors']
return [self._to_size(flavor) for flavor in flavors]
- def _to_images(self, obj, ex_only_active):
- images = obj['images']
- rv = []
- for image in images:
- if ex_only_active and image.get('status') != 'ACTIVE':
- continue
- rv.append(self._to_image(image))
- return rv
-
def _create_args_to_params(self, node, kwargs):
server_params = {
'name': kwargs.get('name'),
@@ -830,26 +860,6 @@ class OpenStack_1_1_NodeDriver(OpenStack
return server_params
- def create_node(self, **kwargs):
- """Create a new node
-
- See L{NodeDriver.create_node} for more keyword args.
- @keyword ex_metadata: Key/Value metadata to associate with a node
- @type ex_metadata: C{dict}
-
- @keyword ex_files: File Path => File contents to create on
- the node
- @type ex_files: C{dict}
- """
-
- server_params = self._create_args_to_params(None, kwargs)
-
- resp = self.connection.request("/servers",
- method='POST',
- data={'server': server_params})
-
- return self._to_node(resp.object['server'])
-
def _files_to_personality(self, files):
rv = []
@@ -910,9 +920,8 @@ class OpenStack_1_1_NodeDriver(OpenStack
return self._to_node(
self.connection.request(
'/servers/%s' % (node.id,), method='PUT',
- data={'server': {'name': potential_data['name']}}
- ).object['server']
- )
+ data={'server': {'name': potential_data['name']}})
+ .object['server'])
def ex_get_size(self, size_id):
return self._to_size(self.connection.request('/flavors/%s' %
@@ -981,20 +990,6 @@ class OpenStack_1_1_NodeDriver(OpenStack
driver=self,
)
- def _to_image(self, api_image):
- return NodeImage(
- id=api_image['id'],
- name=api_image['name'],
- driver=self,
- extra=dict(
- updated=api_image['updated'],
- created=api_image['created'],
- status=api_image['status'],
- progress=api_image.get('progress'),
- metadata=api_image.get('metadata'),
- ),
- )
-
def _get_size_price(self, size_id):
try:
return get_size_price(
Modified: libcloud/trunk/libcloud/compute/drivers/opsource.py
URL:
http://svn.apache.org/viewvc/libcloud/trunk/libcloud/compute/drivers/opsource.py?rev=1187872&r1=1187871&r2=1187872&view=diff
==============================================================================
--- libcloud/trunk/libcloud/compute/drivers/opsource.py (original)
+++ libcloud/trunk/libcloud/compute/drivers/opsource.py Sun Oct 23 12:03:25 2011
@@ -15,34 +15,40 @@
"""
Opsource Driver
"""
-import base64
from xml.etree import ElementTree as ET
+from base64 import b64encode
+import httplib
-from libcloud.utils import fixxpath, findtext, findall
-from libcloud.common.base import ConnectionUserAndKey, Response
-from libcloud.common.types import LibcloudError, InvalidCredsError,
MalformedResponseError
-from libcloud.compute.types import NodeState, Provider
from libcloud.compute.base import NodeDriver, Node, NodeAuthPassword
from libcloud.compute.base import NodeSize, NodeImage, NodeLocation
+from libcloud.common.types import LibcloudError, InvalidCredsError
+from libcloud.common.base import ConnectionUserAndKey, Response
+from libcloud.common.types import MalformedResponseError
+from libcloud.utils import fixxpath, findtext, findall
+from libcloud.compute.types import NodeState, Provider
# Roadmap / TODO:
#
# 0.1 - Basic functionality: create, delete, start, stop, reboot - servers
-# (base OS images only, no customer images
suported yet)
+# (base OS images only, no customer images suported yet)
# x implement list_nodes()
-# x implement create_node() (only support Base OS images, no customer
images yet)
+# x implement create_node() (only support Base OS images,
+# no customer images yet)
# x implement reboot()
# x implement destroy_node()
# x implement list_sizes()
-# x implement list_images() (only support Base OS images, no customer
images yet)
+# x implement list_images() (only support Base OS images,
+# no customer images yet)
# x implement list_locations()
-# x implement ex_* extension functions for opsource-specific features
+# x implement ex_* extension functions for opsource-specific featurebody
=s
# x ex_graceful_shutdown
# x ex_start_node
# x ex_power_off
# x ex_list_networks (needed for create_node())
-# x refactor: switch to using fixxpath() from the vcloud driver for dealing
with xml namespace tags
-# x refactor: move some functionality from OpsourceConnection.request()
method into new .request_with_orgId() method
+# x refactor: switch to using fixxpath() from the vcloud driver for
+# dealing with xml namespace tags
+# x refactor: move some functionality from OpsourceConnection.request()
+# method into new .request_with_orgId() method
# x add OpsourceStatus object support to:
# x _to_node()
# x _to_network()
@@ -67,19 +73,19 @@ from libcloud.compute.base import NodeSi
# 1.0 - Opsource 0.9 API feature complete, tested
# setup a few variables to represent all of the opsource cloud namespaces
-NAMESPACE_BASE = "http://oec.api.opsource.net/schemas"
-ORGANIZATION_NS = NAMESPACE_BASE + "/organization"
-SERVER_NS = NAMESPACE_BASE + "/server"
-NETWORK_NS = NAMESPACE_BASE + "/network"
-DIRECTORY_NS = NAMESPACE_BASE + "/directory"
-RESET_NS = NAMESPACE_BASE + "/reset"
-VIP_NS = NAMESPACE_BASE + "/vip"
+NAMESPACE_BASE = "http://oec.api.opsource.net/schemas"
+ORGANIZATION_NS = NAMESPACE_BASE + "/organization"
+SERVER_NS = NAMESPACE_BASE + "/server"
+NETWORK_NS = NAMESPACE_BASE + "/network"
+DIRECTORY_NS = NAMESPACE_BASE + "/directory"
+RESET_NS = NAMESPACE_BASE + "/reset"
+VIP_NS = NAMESPACE_BASE + "/vip"
IMAGEIMPORTEXPORT_NS = NAMESPACE_BASE + "/imageimportexport"
-DATACENTER_NS = NAMESPACE_BASE + "/datacenter"
-SUPPORT_NS = NAMESPACE_BASE + "/support"
-GENERAL_NS = NAMESPACE_BASE + "/general"
-IPPLAN_NS = NAMESPACE_BASE + "/ipplan"
-WHITELABEL_NS = NAMESPACE_BASE + "/whitelabel"
+DATACENTER_NS = NAMESPACE_BASE + "/datacenter"
+SUPPORT_NS = NAMESPACE_BASE + "/support"
+GENERAL_NS = NAMESPACE_BASE + "/general"
+IPPLAN_NS = NAMESPACE_BASE + "/ipplan"
+WHITELABEL_NS = NAMESPACE_BASE + "/whitelabel"
class OpsourceResponse(Response):
@@ -88,28 +94,37 @@ class OpsourceResponse(Response):
try:
body = ET.XML(self.body)
except:
- raise MalformedResponseError("Failed to parse XML",
body=self.body, driver=OpsourceNodeDriver)
+ raise MalformedResponseError(
+ 'Failed to parse XML',
+ body=self.body,
+ driver=OpsourceNodeDriver)
+
return body
def parse_error(self):
- if self.status == 401:
+ if self.status == httplib.UNAUTHORIZED:
raise InvalidCredsError(self.body)
-
- if self.status == 403:
+ elif self.status == httplib.FORBIDDEN:
raise InvalidCredsError(self.body)
try:
body = ET.XML(self.body)
except:
- raise MalformedResponseError("Failed to parse XML",
body=self.body, driver=OpsourceNodeDriver)
+ raise MalformedResponseError(
+ 'Failed to parse XML',
+ body=self.body,
+ driver=OpsourceNodeDriver)
- if self.status == 400:
+ if self.status == httplib.BAD_REQUEST:
code = findtext(body, 'resultCode', SERVER_NS)
message = findtext(body, 'resultDetail', SERVER_NS)
- raise OpsourceAPIException(code, message,
driver=OpsourceNodeDriver)
+ raise OpsourceAPIException(code,
+ message,
+ driver=OpsourceNodeDriver)
return self.body
+
class OpsourceAPIException(LibcloudError):
def __init__(self, code, msg, driver):
self.code = code
@@ -120,7 +135,9 @@ class OpsourceAPIException(LibcloudError
return "%s: %s" % (self.code, self.msg)
def __repr__(self):
- return "<OpsourceAPIException: code='%s', msg='%s'>" % (self.code,
self.msg)
+ return ("<OpsourceAPIException: code='%s', msg='%s'>" %
+ (self.code, self.msg))
+
class OpsourceConnection(ConnectionUserAndKey):
"""
@@ -134,45 +151,49 @@ class OpsourceConnection(ConnectionUserA
responseCls = OpsourceResponse
def add_default_headers(self, headers):
- headers['Authorization'] = ('Basic %s'
- % (base64.b64encode('%s:%s' % (self.user_id,
self.key))))
+ headers['Authorization'] = ('Basic %s' % b64encode('%s:%s' %
+ (self.user_id, self.key)))
return headers
- def request(self, action, params=None, data='', headers=None,
method='GET'):
+ def request(self, action, params=None, data='',
+ headers=None, method='GET'):
action = "%s/%s/%s" % (self.api_path, self.api_version, action)
return super(OpsourceConnection, self).request(
action=action,
params=params, data=data,
- method=method, headers=headers
- )
+ method=method, headers=headers)
- def request_with_orgId(self, action, params=None, data='', headers=None,
method='GET'):
+ def request_with_orgId(self, action, params=None, data='',
+ headers=None, method='GET'):
action = "%s/%s" % (self.get_resource_path(), action)
return super(OpsourceConnection, self).request(
action=action,
params=params, data=data,
- method=method, headers=headers
- )
+ method=method, headers=headers)
def get_resource_path(self):
- """this method returns a resource path which is necessary for
referencing
- resources that require a full path instead of just an ID, such as
- networks, and customer snapshots.
"""
- return ("%s/%s/%s" % (self.api_path, self.api_version,
self._get_orgId()))
+ This method returns a resource path which is necessary for referencing
+ resources that require a full path instead of just an ID, such as
+ networks, and customer snapshots.
+ """
+ return ("%s/%s/%s" % (self.api_path, self.api_version,
+ self._get_orgId()))
def _get_orgId(self):
"""
- send the /myaccount API request to opsource cloud and parse the
'orgId' from the
- XML response object. We need the orgId to use most of the other API
functions
+ Send the /myaccount API request to opsource cloud and parse the
+ 'orgId' from the XML response object. We need the orgId to use most
+ of the other API functions
"""
if self._orgId == None:
body = self.request('myaccount').object
self._orgId = findtext(body, 'orgId', DIRECTORY_NS)
return self._orgId
+
class OpsourceStatus(object):
"""
Opsource API pending operation status class
@@ -181,7 +202,8 @@ class OpsourceStatus(object):
"""
def __init__(self, action=None, requestTime=None, userName=None,
numberOfSteps=None, updateTime=None, step_name=None,
- step_number=None, step_percentComplete=None,
failureReason=None):
+ step_number=None, step_percentComplete=None,
+ failureReason=None):
self.action = action
self.requestTime = requestTime
self.userName = userName
@@ -195,15 +217,17 @@ class OpsourceStatus(object):
def __repr__(self):
return (('<OpsourceStatus: action=%s, requestTime=%s, userName=%s, ' \
'numberOfSteps=%s, updateTime=%s, step_name=%s, ' \
- 'step_number=%s, step_percentComplete=%s,
failureReason=%s')
+ 'step_number=%s, step_percentComplete=%s, ' \
+ 'failureReason=%s')
% (self.action, self.requestTime, self.userName,
self.numberOfSteps, self.updateTime, self.step_name,
self.step_number, self.step_percentComplete,
self.failureReason))
+
class OpsourceNetwork(object):
"""
- Opsource network with location
+ Opsource network with location.
"""
def __init__(self, id, name, description, location, privateNet,
@@ -217,53 +241,25 @@ class OpsourceNetwork(object):
self.status = status
def __repr__(self):
- return (('<OpsourceNetwork: id=%s, name=%s, description=%s,
location=%s, ' \
- 'privateNet=%s, multicast=%s>')
+ return (('<OpsourceNetwork: id=%s, name=%s, description=%s, ' \
+ 'location=%s, privateNet=%s, multicast=%s>')
% (self.id, self.name, self.description, self.location,
self.privateNet, self.multicast))
class OpsourceNodeDriver(NodeDriver):
"""
- Opsource node driver
+ Opsource node driver.
"""
connectionCls = OpsourceConnection
-
- type = Provider.OPSOURCE
name = 'Opsource'
-
+ type = Provider.OPSOURCE
features = {"create_node": ["password"]}
- def list_nodes(self):
- nodes =
self._to_nodes(self.connection.request_with_orgId('server/deployed').object)
-
nodes.extend(self._to_nodes(self.connection.request_with_orgId('server/pendingDeploy').object))
- return nodes
-
- def list_sizes(self, location=None):
- return [ NodeSize(id=1,
- name="default",
- ram=0,
- disk=0,
- bandwidth=0,
- price=0,
- driver=self.connection.driver) ]
-
- def list_images(self, location=None):
- """return a list of available images
- Currently only returns the default 'base OS images' provided by
opsource.
- Customer images (snapshots) are not yet supported.
- """
- return
self._to_base_images(self.connection.request('base/image').object)
-
- def list_locations(self):
- """list locations (datacenters) available for instantiating servers and
- networks.
- """
- return
self._to_locations(self.connection.request_with_orgId('datacenter').object)
-
def create_node(self, **kwargs):
- """Create a new opsource node
+ """
+ Create a new opsource node
Standard keyword arguments from L{NodeDriver.create_node}:
@keyword name: String with a name for this new node (required)
@@ -272,7 +268,8 @@ class OpsourceNodeDriver(NodeDriver):
@keyword image: OS Image to boot on node. (required)
@type image: L{NodeImage}
- @keyword auth: Initial authentication information for the node
(required)
+ @keyword auth: Initial authentication information for the
+ node (required)
@type auth: L{NodeAuthPassword}
Non-standard keyword arguments:
@@ -282,21 +279,24 @@ class OpsourceNodeDriver(NodeDriver):
@keyword ex_network: Network to create the node within (required)
@type ex_network: L{OpsourceNetwork}
- @keyword ex_isStarted: Start server after creation? default true
(required)
+ @keyword ex_isStarted: Start server after creation? default
+ true (required)
@type ex_isStarted: C{bool}
- @return: The newly created L{Node}. NOTE: Opsource does not provide a
way to
- determine the ID of the server that was just created, so the
returned
- L{Node} is not guaranteed to be the same one that was
created. This
- is only the case when multiple nodes with the same name exist.
+ @return: The newly created L{Node}. NOTE: Opsource does not provide a
+ way to determine the ID of the server that was just created,
+ so the returned L{Node} is not guaranteed to be the same one
+ that was created. This is only the case when multiple nodes
+ with the same name exist.
"""
name = kwargs['name']
image = kwargs['image']
- # XXX: Node sizes can be adjusted after a node is created, but cannot
be
- # set at create time because size is part of the image
definition.
+ # XXX: Node sizes can be adjusted after a node is created, but
+ # cannot be set at create time because size is part of the
+ # image definition.
password = None
- if kwargs.has_key('auth'):
+ if 'auth' in kwargs:
auth = kwargs.get('auth')
if isinstance(auth, NodeAuthPassword):
password = auth.password
@@ -309,13 +309,15 @@ class OpsourceNodeDriver(NodeDriver):
ex_network = kwargs.get('ex_network')
if not isinstance(ex_network, OpsourceNetwork):
raise ValueError('ex_network must be of OpsourceNetwork type')
- vlanResourcePath = "%s/%s" % (self.connection.get_resource_path(),
ex_network.id)
+ vlanResourcePath = "%s/%s" % (self.connection.get_resource_path(),
+ ex_network.id)
imageResourcePath = None
- if image.extra.has_key('resourcePath'):
+ if 'resourcePath' in image.extra:
imageResourcePath = image.extra['resourcePath']
else:
- imageResourcePath = "%s/%s" %
(self.connection.get_resource_path(), image.id)
+ imageResourcePath = "%s/%s" % (self.connection.get_resource_path(),
+ image.id)
server_elm = ET.Element('Server', {'xmlns': SERVER_NS})
ET.SubElement(server_elm, "name").text = name
@@ -326,59 +328,150 @@ class OpsourceNodeDriver(NodeDriver):
ET.SubElement(server_elm, "isStarted").text = str(ex_isStarted)
self.connection.request_with_orgId('server',
- method='POST',
- data=ET.tostring(server_elm)
- ).object
+ method='POST',
+ data=ET.tostring(server_elm)).object
+
# XXX: return the last node in the list that has a matching name. this
# is likely but not guaranteed to be the node we just created
# because opsource allows multiple nodes to have the same name
return filter(lambda x: x.name == name, self.list_nodes())[-1]
- def reboot_node(self, node):
- """reboots the node"""
- body = self.connection.request_with_orgId('server/%s?restart' %
node.id).object
+ def destroy_node(self, node):
+ body = self.connection.request_with_orgId('server/%s?delete' %
+ (node.id)).object
+
result = findtext(body, 'result', GENERAL_NS)
return result == 'SUCCESS'
- def destroy_node(self, node):
- """Destroys the node"""
- body = self.connection.request_with_orgId('server/%s?delete' %
node.id).object
+ def reboot_node(self, node):
+ body = self.connection.request_with_orgId('server/%s?restart' %
+ (node.id)).object
result = findtext(body, 'result', GENERAL_NS)
return result == 'SUCCESS'
+ def list_nodes(self):
+ nodes = self._to_nodes(self.connection
+ .request_with_orgId('server/deployed').object)
+ nodes.extend(self._to_nodes(self.connection
+ .request_with_orgId('server/pendingDeploy').object))
+ return nodes
+
+ def list_images(self, location=None):
+ """
+ return a list of available images
+ Currently only returns the default 'base OS images' provided by
+ opsource. Customer images (snapshots) are not yet supported.
+ """
+ return self._to_base_images(self.connection.request('base/image')
+ .object)
+
+ def list_sizes(self, location=None):
+ return [
+ NodeSize(id=1,
+ name="default",
+ ram=0,
+ disk=0,
+ bandwidth=0,
+ price=0,
+ driver=self.connection.driver),
+ ]
+
+ def list_locations(self):
+ """
+ list locations (datacenters) available for instantiating servers and
+ networks.
+ """
+ return self._to_locations(self.connection
+ .request_with_orgId('datacenter').object)
+
+ def list_networks(self, location=None):
+ """
+ List networks deployed across all data center locations for your
+ organization. The response includes the location of each network.
+
+ Returns a list of OpsourceNetwork objects
+ """
+ return self._to_networks(self.connection
+ .request_with_orgId('networkWithLocation').object)
+
+ def _to_base_images(self, object):
+ images = []
+ for element in object.findall(fixxpath("ServerImage", SERVER_NS)):
+ images.append(self._to_base_image(element))
+
+ return images
+
+ def _to_base_image(self, element):
+ # Eventually we will probably need multiple _to_image() functions
+ # that parse <ServerImage> differently than <DeployedImage>.
+ # DeployedImages are customer snapshot images, and ServerImages are
+ # 'base' images provided by opsource
+ location_id = findtext(element, 'location', SERVER_NS)
+ location = self.ex_get_location_by_id(location_id)
+
+ extra = {
+ 'description': findtext(element, 'description', SERVER_NS),
+ 'OS_type': findtext(element, 'operatingSystem/type', SERVER_NS),
+ 'OS_displayName': findtext(element, 'operatingSystem/displayName',
+ SERVER_NS),
+ 'cpuCount': findtext(element, 'cpuCount', SERVER_NS),
+ 'resourcePath': findtext(element, 'resourcePath', SERVER_NS),
+ 'memory': findtext(element, 'memory', SERVER_NS),
+ 'osStorage': findtext(element, 'osStorage', SERVER_NS),
+ 'additionalStorage': findtext(element, 'additionalStorage',
+ SERVER_NS),
+ 'created': findtext(element, 'created', SERVER_NS),
+ 'location': location,
+ }
+
+ return NodeImage(id=str(findtext(element, 'id', SERVER_NS)),
+ name=str(findtext(element, 'name', SERVER_NS)),
+ extra=extra,
+ driver=self.connection.driver)
+
def ex_start_node(self, node):
- """Powers on an existing deployed server"""
- body = self.connection.request_with_orgId('server/%s?start' %
node.id).object
+ """
+ Powers on an existing deployed server
+ """
+ body = self.connection.request_with_orgId('server/%s?start' %
+ node.id).object
result = findtext(body, 'result', GENERAL_NS)
return result == 'SUCCESS'
def ex_shutdown_graceful(self, node):
- """This function will attempt to "gracefully" stop a server by
initiating a
- shutdown sequence within the guest operating system. A successful
response
- on this function means the system has successfully passed the
- request into the operating system.
"""
- body = self.connection.request_with_orgId('server/%s?shutdown' %
node.id).object
+ This function will attempt to "gracefully" stop a server by
+ initiating a shutdown sequence within the guest operating system.
+ A successful response on this function means the system has
+ successfully passed the request into the operating system.
+ """
+ body = self.connection.request_with_orgId('server/%s?shutdown' %
+ (node.id)).object
result = findtext(body, 'result', GENERAL_NS)
return result == 'SUCCESS'
def ex_power_off(self, node):
- """This function will abruptly power-off a server. Unlike
ex_shutdown_graceful,
- success ensures the node will stop but some OS and application
configurations may
- be adversely affected by the equivalent of pulling the power plug out
of the
- machine.
"""
- body = self.connection.request_with_orgId('server/%s?poweroff' %
node.id).object
+ This function will abruptly power-off a server. Unlike
+ ex_shutdown_graceful, success ensures the node will stop but some OS
+ and application configurations may be adversely affected by the
+ equivalent of pulling the power plug out of the machine.
+ """
+ body = self.connection.request_with_orgId('server/%s?poweroff' %
+ node.id).object
result = findtext(body, 'result', GENERAL_NS)
return result == 'SUCCESS'
def ex_list_networks(self):
- """List networks deployed across all data center locations for your
+ """
+ List networks deployed across all data center locations for your
organization. The response includes the location of each network.
Returns a list of OpsourceNetwork objects
"""
- return
self._to_networks(self.connection.request_with_orgId('networkWithLocation').object)
+ response = self.connection.request_with_orgId('networkWithLocation') \
+ .object
+ return self._to_networks(response)
def ex_get_location_by_id(self, id):
location = None
@@ -387,8 +480,11 @@ class OpsourceNodeDriver(NodeDriver):
return location
def _to_networks(self, object):
- node_elements = findall(object, 'network', NETWORK_NS)
- return [ self._to_network(el) for el in node_elements ]
+ networks = []
+ for element in findall(object, 'network', NETWORK_NS):
+ networks.append(self._to_network(element))
+
+ return networks
def _to_network(self, element):
multicast = False
@@ -402,15 +498,20 @@ class OpsourceNodeDriver(NodeDriver):
return OpsourceNetwork(id=findtext(element, 'id', NETWORK_NS),
name=findtext(element, 'name', NETWORK_NS),
- description=findtext(element, 'description',
NETWORK_NS),
+ description=findtext(element, 'description',
+ NETWORK_NS),
location=location,
- privateNet=findtext(element, 'privateNet',
NETWORK_NS),
+ privateNet=findtext(element, 'privateNet',
+ NETWORK_NS),
multicast=multicast,
status=status)
def _to_locations(self, object):
- node_elements = object.findall(fixxpath('datacenter', DATACENTER_NS))
- return [ self._to_location(el) for el in node_elements ]
+ locations = []
+ for element in object.findall(fixxpath('datacenter', DATACENTER_NS)):
+ locations.append(self._to_location(element))
+
+ return locations
def _to_location(self, element):
l = NodeLocation(id=findtext(element, 'location', DATACENTER_NS),
@@ -421,12 +522,13 @@ class OpsourceNodeDriver(NodeDriver):
def _to_nodes(self, object):
node_elements = object.findall(fixxpath('DeployedServer', SERVER_NS))
- node_elements.extend(object.findall(fixxpath('PendingDeployServer',
SERVER_NS)))
- return [ self._to_node(el) for el in node_elements ]
+ node_elements.extend(object.findall(fixxpath('PendingDeployServer',
+ SERVER_NS)))
+ return [self._to_node(el) for el in node_elements]
def _to_node(self, element):
if findtext(element, 'isStarted', SERVER_NS) == 'true':
- state = NodeState.RUNNING
+ state = NodeState.RUNNING
else:
state = NodeState.TERMINATED
@@ -438,12 +540,18 @@ class OpsourceNodeDriver(NodeDriver):
'networkId': findtext(element, 'networkId', SERVER_NS),
'machineName': findtext(element, 'machineName', SERVER_NS),
'deployedTime': findtext(element, 'deployedTime', SERVER_NS),
- 'cpuCount': findtext(element, 'machineSpecification/cpuCount',
SERVER_NS),
- 'memoryMb': findtext(element, 'machineSpecification/memoryMb',
SERVER_NS),
- 'osStorageGb': findtext(element,
'machineSpecification/osStorageGb', SERVER_NS),
- 'additionalLocalStorageGb': findtext(element,
'machineSpecification/additionalLocalStorageGb', SERVER_NS),
- 'OS_type': findtext(element,
'machineSpecification/operatingSystem/type', SERVER_NS),
- 'OS_displayName': findtext(element,
'machineSpecification/operatingSystem/displayName', SERVER_NS),
+ 'cpuCount': findtext(element, 'machineSpecification/cpuCount',
+ SERVER_NS),
+ 'memoryMb': findtext(element, 'machineSpecification/memoryMb',
+ SERVER_NS),
+ 'osStorageGb': findtext(element,
+ 'machineSpecification/osStorageGb', SERVER_NS),
+ 'additionalLocalStorageGb': findtext(element,
+ 'machineSpecification/additionalLocalStorageGb', SERVER_NS),
+ 'OS_type': findtext(element,
+ 'machineSpecification/operatingSystem/type', SERVER_NS),
+ 'OS_displayName': findtext(element,
+ 'machineSpecification/operatingSystem/displayName', SERVER_NS),
'status': status,
}
@@ -456,46 +564,22 @@ class OpsourceNodeDriver(NodeDriver):
extra=extra)
return n
- def _to_base_images(self, object):
- node_elements = object.findall(fixxpath("ServerImage", SERVER_NS))
- return [ self._to_base_image(el) for el in node_elements ]
-
- def _to_base_image(self, element):
- # Eventually we will probably need multiple _to_image() functions
- # that parse <ServerImage> differently than <DeployedImage>.
- # DeployedImages are customer snapshot images, and ServerImages are
- # 'base' images provided by opsource
- location_id = findtext(element, 'location', SERVER_NS)
- location = self.ex_get_location_by_id(location_id)
-
- extra = {
- 'description': findtext(element, 'description', SERVER_NS),
- 'OS_type': findtext(element, 'operatingSystem/type', SERVER_NS),
- 'OS_displayName': findtext(element, 'operatingSystem/displayName',
SERVER_NS),
- 'cpuCount': findtext(element, 'cpuCount', SERVER_NS),
- 'resourcePath': findtext(element, 'resourcePath', SERVER_NS),
- 'memory': findtext(element, 'memory', SERVER_NS),
- 'osStorage': findtext(element, 'osStorage', SERVER_NS),
- 'additionalStorage': findtext(element, 'additionalStorage',
SERVER_NS),
- 'created': findtext(element, 'created', SERVER_NS),
- 'location': location,
- }
-
- i = NodeImage(id=str(findtext(element, 'id', SERVER_NS)),
- name=str(findtext(element, 'name', SERVER_NS)),
- extra=extra,
- driver=self.connection.driver)
- return i
-
def _to_status(self, element):
if element == None:
return OpsourceStatus()
s = OpsourceStatus(action=findtext(element, 'action', SERVER_NS),
- requestTime=findtext(element, 'requestTime',
SERVER_NS),
- userName=findtext(element, 'userName', SERVER_NS),
- numberOfSteps=findtext(element, 'numberOfSteps',
SERVER_NS),
- step_name=findtext(element, 'step/name', SERVER_NS),
- step_number=findtext(element, 'step_number',
SERVER_NS),
- step_percentComplete=findtext(element,
'step/percentComplete', SERVER_NS),
- failureReason=findtext(element, 'failureReason',
SERVER_NS))
+ requestTime=findtext(element, 'requestTime',
+ SERVER_NS),
+ userName=findtext(element, 'userName',
+ SERVER_NS),
+ numberOfSteps=findtext(element, 'numberOfSteps',
+ SERVER_NS),
+ step_name=findtext(element, 'step/name',
+ SERVER_NS),
+ step_number=findtext(element, 'step_number',
+ SERVER_NS),
+ step_percentComplete=findtext(element,
+ 'step/percentComplete', SERVER_NS),
+ failureReason=findtext(element, 'failureReason',
+ SERVER_NS))
return s