=== modified file 'libcloud/compute/drivers/openstack.py'
--- libcloud/compute/drivers/openstack.py	2011-10-20 21:09:25 +0000
+++ libcloud/compute/drivers/openstack.py	2011-10-22 22:36:13 +0000
@@ -23,19 +23,20 @@
 
 import os
 
+import warnings
+import httplib
 import base64
-import httplib
-import warnings
 
 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 NodeSize, NodeImage
 from libcloud.compute.base import NodeDriver, Node
-from libcloud.compute.base import NodeSize, NodeImage
-from libcloud.common.openstack import OpenStackBaseConnection
+from libcloud.pricing import get_size_price
+from libcloud.common.base import Response
+import libcloud.utils
 
 __all__ = [
     'OpenStack_1_0_Response',
@@ -46,33 +47,15 @@
     'OpenStack_1_1_Response',
     'OpenStack_1_1_Connection',
     'OpenStack_1_1_NodeDriver',
-    'OpenStackNodeDriver'
-    ]
-
+    '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,36 @@
         return super(OpenStackComputeConnection, self).request(
             action=action,
             params=params, data=data,
-            method=method, headers=headers
-        )
+            method=method, headers=headers)
 
 
 class OpenStackNodeDriver(NodeDriver):
+    """
+    OpenStack node driver.
+    """
+
+    connectionCls = OpenStackComputeConnection
+    name = 'OpenStack'
+    type = Provider.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,
+    }
 
     def __new__(cls, key, secret=None, secure=True, host=None, port=None,
                  api_version=DEFAULT_API_VERSION, **kwargs):
@@ -163,10 +171,34 @@
             else:
                 raise NotImplementedError(
                     "No OpenStackNodeDriver found for API version %s" %
-                    (api_version)
-                )
+                    (api_version))
         return super(OpenStackNodeDriver, cls).__new__(cls)
 
+    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 _ex_connection_class_kwargs(self):
         rv = {}
         if self._ex_force_base_url:
@@ -177,18 +209,6 @@
             rv['ex_force_auth_version'] = self._ex_force_auth_version
         return rv
 
-    def list_nodes(self):
-        return self._to_nodes(self.connection.request('/servers/detail')
-                                             .object)
-
-    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_get_node_details(self, node_id):
         # @TODO: Remove this if in 0.6
         if isinstance(node_id, Node):
@@ -201,27 +221,14 @@
 
         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 +262,6 @@
 
     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 +271,25 @@
         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 utils.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 +307,14 @@
         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 +331,7 @@
         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 +359,25 @@
                                        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.
@@ -368,13 +392,13 @@
             'resize',
             {'xmlns': self.XML_NAMESPACE,
              'flavorId': str(size.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_confirm_resize(self, node):
         """
@@ -389,13 +413,13 @@
         """
         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):
         """
@@ -410,13 +434,13 @@
         """
         elm = ET.Element(
             'revertResize',
-            {'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_rebuild(self, node_id, image_id):
         # @TODO: Remove those ifs in 0.6
@@ -430,12 +454,13 @@
             'rebuild',
             {'xmlns': self.XML_NAMESPACE,
              '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
@@ -446,13 +471,13 @@
             'sharedIpGroup',
             {'xmlns': self.XML_NAMESPACE,
              'name': group_name,
-            }
+            },
         )
 
         if node_id:
             ET.SubElement(group_elm,
                 'server',
-                {'id': node_id}
+                {'id': node_id},
             )
 
         resp = self.connection.request('/shared_ip_groups',
@@ -464,13 +489,14 @@
         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 = utils.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 +512,7 @@
             '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 +520,7 @@
         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 +531,7 @@
 
         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 +569,7 @@
 
     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 +581,12 @@
         return resp
 
     def _to_nodes(self, object):
-        node_elements = self._findall(object, 'server')
+        node_elements = utils.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(utils.findall(obj, 'server',
+                                           self.XML_NAMESPACE)[0])
 
     def _to_node(self, el):
         def get_ips(el):
@@ -579,11 +598,12 @@
                 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(utils.findall(el, 'addresses/public/ip',
+                                          self.XML_NAMESPACE))
+        private_ip = get_ips(utils.findall(el, 'addresses/private/ip',
+                                          self.XML_NAMESPACE))
+        metadata = get_meta_dict(utils.findall(el, 'metadata/meta',
+                                          self.XML_NAMESPACE))
 
         n = Node(id=el.get('id'),
                  name=el.get('name'),
@@ -605,11 +625,11 @@
         return n
 
     def _to_sizes(self, object):
-        elements = self._findall(object, 'flavor')
+        elements = utils.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 +638,6 @@
                      # 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 +660,11 @@
             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 utils.findall(limits, 'rate/limit',
+            self.XML_NAMESPACE)]
         absolute = {}
-        for item in self._findall(limits, 'absolute/limit'):
+        for item in utils.findall(limits, 'absolute/limit',
+          self.XML_NAMESPACE):
             absolute.update(_to_absolute(item))
 
         return {"rate": rate, "absolute": absolute}
@@ -681,8 +682,7 @@
                 '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 +696,14 @@
         """
         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 = utils.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 utils.findall(servers_el[0], 'server',
+                       self.XML_NAMESPACE)]
         else:
             servers = None
         return OpenStack_1_0_SharedIpGroup(id=el.get('id'),
@@ -712,10 +713,11 @@
     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')],
+             utils.findall(utils.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')]
-        )
+             utils.findall(utils.findall(el, 'private', self.XML_NAMESPACE)[0],
+             'ip', self.XML_NAMESPACE)])
 
     def _get_size_price(self, size_id):
         try:
@@ -747,7 +749,7 @@
         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 +779,6 @@
 
     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 +788,49 @@
                                                     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,21 +839,12 @@
         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'),
             'metadata': kwargs.get('ex_metadata', {}),
             'personality': self._files_to_personality(kwargs.get("ex_files",
-                                                                 {}))
+                                                                 {})),
         }
 
         if 'name' in kwargs:
@@ -830,26 +864,6 @@
 
         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 +924,8 @@
         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 +994,6 @@
             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 file 'libcloud/compute/drivers/opsource.py'
--- libcloud/compute/drivers/opsource.py	2011-10-12 21:00:33 +0000
+++ libcloud/compute/drivers/opsource.py	2011-10-22 19:11:45 +0000
@@ -15,34 +15,40 @@
 """
 Opsource Driver
 """
-import base64
 from xml.etree import ElementTree as ET
+from base64 import b64encode
+import httplib
 
+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.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
 
 # 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 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,49 +73,60 @@
 # 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):
 
     def parse_body(self):
+        if self.status == httplib.NO_CONTENT or not self.body:
+            return None
+
         try:
-            body = ET.XML(self.body)
+            return ET.XML(self.body)
         except:
-            raise MalformedResponseError("Failed to parse XML", body=self.body, driver=OpsourceNodeDriver)
-        return body
+            raise MalformedResponseError(
+                'Failed to parse XML',
+                body=self.body,
+                driver=OpsourceNodeDriver)
+
+        return self.body
 
     def parse_error(self):
-        if self.status == 401:
-            raise InvalidCredsError(self.body)
-
-        if self.status == 403:
-            raise InvalidCredsError(self.body)
-
-        try:
-            body = ET.XML(self.body)
-        except:
-            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)
+        elif self.status == httplib.UNAUTHORIZED:
+            raise InvalidCredsError(self.body)
+        elif self.status == httplib.FORBIDDEN:
+            raise InvalidCredsError(self.body)
+
+        try:
+            return ET.XML(self.body)
+        except:
+            raise MalformedResponseError(
+                'Failed to parse XML',
+                body=self.body,
+                driver=OpsourceNodeDriver)
 
         return self.body
 
+
 class OpsourceAPIException(LibcloudError):
     def __init__(self, code, msg, driver):
         self.code = code
@@ -120,7 +137,9 @@
         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 +153,49 @@
     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 +204,8 @@
     """
     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 +219,17 @@
     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 +243,25 @@
         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
-
+    name = 'Opsource'
     type = Provider.OPSOURCE
-    name = '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 +270,8 @@
         @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 +281,24 @@
         @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 +311,15 @@
         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
@@ -327,59 +331,140 @@
 
         self.connection.request_with_orgId('server',
                                            method='POST',
-                                           data=ET.tostring(server_elm)
-                                           ).object
+                                           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 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 reboot_node(self, node):
-        """reboots the node"""
-        body = self.connection.request_with_orgId('server/%s?restart' % 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
-        result = findtext(body, 'result', GENERAL_NS)
-        return result == 'SUCCESS'
+        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
-        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 ex_get_location_by_id(self, id):
         location = None
         if id is not None:
@@ -387,8 +472,11 @@
         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 +490,20 @@
 
         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 +514,13 @@
 
     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 +532,18 @@
             '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 +556,22 @@
                  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

