You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@libcloud.apache.org by an...@apache.org on 2016/11/14 23:51:09 UTC

[22/56] [abbrv] libcloud git commit: Removed sdist

http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/opennebula.py
----------------------------------------------------------------------
diff --git a/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/opennebula.py b/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/opennebula.py
deleted file mode 100644
index c295cd4..0000000
--- a/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/opennebula.py
+++ /dev/null
@@ -1,1264 +0,0 @@
-# Copyright 2002-2009, Distributed Systems Architecture Group, Universidad
-# Complutense de Madrid (dsa-research.org)
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""
-OpenNebula.org driver.
-"""
-
-__docformat__ = 'epytext'
-
-from base64 import b64encode
-import hashlib
-
-try:
-    from lxml import etree as ET
-except ImportError:
-    from xml.etree import ElementTree as ET
-
-from libcloud.utils.py3 import httplib
-from libcloud.utils.py3 import next
-from libcloud.utils.py3 import b
-
-from libcloud.compute.base import NodeState, NodeDriver, Node, NodeLocation
-from libcloud.common.base import ConnectionUserAndKey, XmlResponse
-from libcloud.compute.base import NodeImage, NodeSize, StorageVolume
-from libcloud.common.types import InvalidCredsError
-from libcloud.compute.providers import Provider
-
-__all__ = [
-    'ACTION',
-    'OpenNebulaResponse',
-    'OpenNebulaConnection',
-    'OpenNebulaNodeSize',
-    'OpenNebulaNetwork',
-    'OpenNebulaNodeDriver',
-    'OpenNebula_1_4_NodeDriver',
-    'OpenNebula_2_0_NodeDriver',
-    'OpenNebula_3_0_NodeDriver',
-    'OpenNebula_3_2_NodeDriver',
-    'OpenNebula_3_8_NodeDriver']
-
-API_HOST = ''
-API_PORT = (4567, 443)
-API_SECURE = True
-API_PLAIN_AUTH = False
-DEFAULT_API_VERSION = '3.2'
-
-
-class ACTION(object):
-    """
-    All actions, except RESUME, only apply when the VM is in the "Running"
-    state.
-    """
-
-    STOP = 'STOPPED'
-    """
-    The VM is stopped, and its memory state stored to a checkpoint file. VM
-    state, and disk image, are transferred back to the front-end. Resuming
-    the VM requires the VM instance to be re-scheduled.
-    """
-
-    SUSPEND = 'SUSPENDED'
-    """
-    The VM is stopped, and its memory state stored to a checkpoint file. The VM
-    state, and disk image, are left on the host to be resumed later. Resuming
-    the VM does not require the VM to be re-scheduled. Rather, after
-    suspending, the VM resources are reserved for later resuming.
-    """
-
-    RESUME = 'RESUME'
-    """
-    The VM is resumed using the saved memory state from the checkpoint file,
-    and the VM's disk image. The VM is either started immediately, or
-    re-scheduled depending on how it was suspended.
-    """
-
-    CANCEL = 'CANCEL'
-    """
-    The VM is forcibly shutdown, its memory state is deleted. If a persistent
-    disk image was used, that disk image is transferred back to the front-end.
-    Any non-persistent disk images are deleted.
-    """
-
-    SHUTDOWN = 'SHUTDOWN'
-    """
-    The VM is gracefully shutdown by sending the ACPI signal. If the VM does
-    not shutdown, then it is considered to still be running. If successfully,
-    shutdown, its memory state is deleted. If a persistent disk image was used,
-    that disk image is transferred back to the front-end. Any non-persistent
-    disk images are deleted.
-    """
-
-    REBOOT = 'REBOOT'
-    """
-    Introduced in OpenNebula v3.2.
-
-    The VM is gracefully restarted by sending the ACPI signal.
-    """
-
-    DONE = 'DONE'
-    """
-    The VM is forcibly shutdown, its memory state is deleted. If a persistent
-    disk image was used, that disk image is transferred back to the front-end.
-    Any non-persistent disk images are deleted.
-    """
-
-
-class OpenNebulaResponse(XmlResponse):
-    """
-    XmlResponse class for the OpenNebula.org driver.
-    """
-
-    def success(self):
-        """
-        Check if response has the appropriate HTTP response code to be a
-        success.
-
-        :rtype:  ``bool``
-        :return: True is success, else False.
-        """
-        i = int(self.status)
-        return i >= 200 and i <= 299
-
-    def parse_error(self):
-        """
-        Check if response contains any errors.
-
-        @raise: :class:`InvalidCredsError`
-
-        :rtype:  :class:`ElementTree`
-        :return: Contents of HTTP response body.
-        """
-        if int(self.status) == httplib.UNAUTHORIZED:
-            raise InvalidCredsError(self.body)
-        return self.body
-
-
-class OpenNebulaConnection(ConnectionUserAndKey):
-    """
-    Connection class for the OpenNebula.org driver.
-    with plain_auth support
-    """
-
-    host = API_HOST
-    port = API_PORT
-    secure = API_SECURE
-    plain_auth = API_PLAIN_AUTH
-    responseCls = OpenNebulaResponse
-
-    def __init__(self, *args, **kwargs):
-        if 'plain_auth' in kwargs:
-            self.plain_auth = kwargs.pop('plain_auth')
-        super(OpenNebulaConnection, self).__init__(*args, **kwargs)
-
-    def add_default_headers(self, headers):
-        """
-        Add headers required by the OpenNebula.org OCCI interface.
-
-        Includes adding Basic HTTP Authorization headers for authenticating
-        against the OpenNebula.org OCCI interface.
-
-        :type  headers: ``dict``
-        :param headers: Dictionary containing HTTP headers.
-
-        :rtype:  ``dict``
-        :return: Dictionary containing updated headers.
-        """
-        if self.plain_auth:
-            passwd = self.key
-        else:
-            passwd = hashlib.sha1(b(self.key)).hexdigest()
-        headers['Authorization'] =\
-            ('Basic %s' % b64encode(b('%s:%s' % (self.user_id,
-                                                 passwd))).decode('utf-8'))
-        return headers
-
-
-class OpenNebulaNodeSize(NodeSize):
-    """
-    NodeSize class for the OpenNebula.org driver.
-    """
-
-    def __init__(self, id, name, ram, disk, bandwidth, price, driver,
-                 cpu=None, vcpu=None):
-        super(OpenNebulaNodeSize, self).__init__(id=id, name=name, ram=ram,
-                                                 disk=disk,
-                                                 bandwidth=bandwidth,
-                                                 price=price, driver=driver)
-        self.cpu = cpu
-        self.vcpu = vcpu
-
-    def __repr__(self):
-        return (('<OpenNebulaNodeSize: id=%s, name=%s, ram=%s, disk=%s, '
-                 'bandwidth=%s, price=%s, driver=%s, cpu=%s, vcpu=%s ...>')
-                % (self.id, self.name, self.ram, self.disk, self.bandwidth,
-                   self.price, self.driver.name, self.cpu, self.vcpu))
-
-
-class OpenNebulaNetwork(object):
-    """
-    Provide a common interface for handling networks of all types.
-
-    Network objects are analogous to physical switches connecting two or
-    more physical nodes together. The Network object provides the interface in
-    libcloud through which we can manipulate networks in different cloud
-    providers in the same way. Network objects don't actually do much directly
-    themselves, instead the network driver handles the connection to the
-    network.
-
-    You don't normally create a network object yourself; instead you use
-    a driver and then have that create the network for you.
-
-    >>> from libcloud.compute.drivers.dummy import DummyNodeDriver
-    >>> driver = DummyNodeDriver()
-    >>> network = driver.create_network()
-    >>> network = driver.list_networks()[0]
-    >>> network.name
-    'dummy-1'
-    """
-
-    def __init__(self, id, name, address, size, driver, extra=None):
-        self.id = str(id)
-        self.name = name
-        self.address = address
-        self.size = size
-        self.driver = driver
-        self.uuid = self.get_uuid()
-        self.extra = extra or {}
-
-    def get_uuid(self):
-        """
-        Unique hash for this network.
-
-        The hash is a function of an SHA1 hash of the network's ID and
-        its driver which means that it should be unique between all
-        networks. In some subclasses (e.g. GoGrid) there is no ID
-        available so the public IP address is used. This means that,
-        unlike a properly done system UUID, the same UUID may mean a
-        different system install at a different time
-
-        >>> from libcloud.network.drivers.dummy import DummyNetworkDriver
-        >>> driver = DummyNetworkDriver()
-        >>> network = driver.create_network()
-        >>> network.get_uuid()
-        'd3748461511d8b9b0e0bfa0d4d3383a619a2bb9f'
-
-        Note, for example, that this example will always produce the
-        same UUID!
-
-        :rtype:  ``str``
-        :return: Unique identifier for this instance.
-        """
-        return hashlib.sha1(b("%s:%s" % (self.id,
-                                         self.driver.type))).hexdigest()
-
-    def __repr__(self):
-        return (('<OpenNebulaNetwork: uuid=%s, name=%s, address=%s, size=%s, '
-                 'provider=%s ...>')
-                % (self.uuid, self.name, self.address, self.size,
-                   self.driver.name))
-
-
-class OpenNebulaNodeDriver(NodeDriver):
-    """
-    OpenNebula.org node driver.
-    """
-
-    connectionCls = OpenNebulaConnection
-    name = 'OpenNebula'
-    website = 'http://opennebula.org/'
-    type = Provider.OPENNEBULA
-
-    NODE_STATE_MAP = {
-        'INIT': NodeState.PENDING,
-        'PENDING': NodeState.PENDING,
-        'HOLD': NodeState.PENDING,
-        'ACTIVE': NodeState.RUNNING,
-        'STOPPED': NodeState.TERMINATED,
-        'SUSPENDED': NodeState.PENDING,
-        'DONE': NodeState.TERMINATED,
-        'FAILED': NodeState.TERMINATED}
-
-    def __new__(cls, key, secret=None, api_version=DEFAULT_API_VERSION,
-                **kwargs):
-        if cls is OpenNebulaNodeDriver:
-            if api_version in ['1.4']:
-                cls = OpenNebula_1_4_NodeDriver
-            elif api_version in ['2.0', '2.2']:
-                cls = OpenNebula_2_0_NodeDriver
-            elif api_version in ['3.0']:
-                cls = OpenNebula_3_0_NodeDriver
-            elif api_version in ['3.2']:
-                cls = OpenNebula_3_2_NodeDriver
-            elif api_version in ['3.6']:
-                cls = OpenNebula_3_6_NodeDriver
-            elif api_version in ['3.8']:
-                cls = OpenNebula_3_8_NodeDriver
-                if 'plain_auth' not in kwargs:
-                    kwargs['plain_auth'] = cls.plain_auth
-                else:
-                    cls.plain_auth = kwargs['plain_auth']
-            else:
-                raise NotImplementedError(
-                    "No OpenNebulaNodeDriver found for API version %s" %
-                    (api_version))
-            return super(OpenNebulaNodeDriver, cls).__new__(cls)
-
-    def create_node(self, **kwargs):
-        """
-        Create a new OpenNebula node.
-
-        @inherits: :class:`NodeDriver.create_node`
-
-        :keyword networks: List of virtual networks to which this node should
-                           connect. (optional)
-        :type    networks: :class:`OpenNebulaNetwork` or
-            ``list`` of :class:`OpenNebulaNetwork`
-        """
-        compute = ET.Element('COMPUTE')
-
-        name = ET.SubElement(compute, 'NAME')
-        name.text = kwargs['name']
-
-        instance_type = ET.SubElement(compute, 'INSTANCE_TYPE')
-        instance_type.text = kwargs['size'].name
-
-        storage = ET.SubElement(compute, 'STORAGE')
-        ET.SubElement(storage,
-                      'DISK',
-                      {'image': '%s' % (str(kwargs['image'].id))})
-
-        if 'networks' in kwargs:
-            if not isinstance(kwargs['networks'], list):
-                kwargs['networks'] = [kwargs['networks']]
-
-            networkGroup = ET.SubElement(compute, 'NETWORK')
-            for network in kwargs['networks']:
-                if network.address:
-                    ET.SubElement(networkGroup, 'NIC',
-                                  {'network': '%s' % (str(network.id)),
-                                   'ip': network.address})
-                else:
-                    ET.SubElement(networkGroup, 'NIC',
-                                  {'network': '%s' % (str(network.id))})
-
-        xml = ET.tostring(compute)
-        node = self.connection.request('/compute', method='POST',
-                                       data=xml).object
-
-        return self._to_node(node)
-
-    def destroy_node(self, node):
-        url = '/compute/%s' % (str(node.id))
-        resp = self.connection.request(url, method='DELETE')
-
-        return resp.status == httplib.OK
-
-    def list_nodes(self):
-        return self._to_nodes(self.connection.request('/compute').object)
-
-    def list_images(self, location=None):
-        return self._to_images(self.connection.request('/storage').object)
-
-    def list_sizes(self, location=None):
-        """
-        Return list of sizes on a provider.
-
-        @inherits: :class:`NodeDriver.list_sizes`
-
-        :return: List of compute node sizes supported by the cloud provider.
-        :rtype:  ``list`` of :class:`OpenNebulaNodeSize`
-        """
-        return [
-            NodeSize(id=1,
-                     name='small',
-                     ram=None,
-                     disk=None,
-                     bandwidth=None,
-                     price=None,
-                     driver=self),
-            NodeSize(id=2,
-                     name='medium',
-                     ram=None,
-                     disk=None,
-                     bandwidth=None,
-                     price=None,
-                     driver=self),
-            NodeSize(id=3,
-                     name='large',
-                     ram=None,
-                     disk=None,
-                     bandwidth=None,
-                     price=None,
-                     driver=self),
-        ]
-
-    def list_locations(self):
-        return [NodeLocation(0, '', '', self)]
-
-    def ex_list_networks(self, location=None):
-        """
-        List virtual networks on a provider.
-
-        :param location: Location from which to request a list of virtual
-                         networks. (optional)
-        :type  location: :class:`NodeLocation`
-
-        :return: List of virtual networks available to be connected to a
-                 compute node.
-        :rtype:  ``list`` of :class:`OpenNebulaNetwork`
-        """
-        return self._to_networks(self.connection.request('/network').object)
-
-    def ex_node_action(self, node, action):
-        """
-        Build action representation and instruct node to commit action.
-
-        Build action representation from the compute node ID, and the
-        action which should be carried out on that compute node. Then
-        instruct the node to carry out that action.
-
-        :param node: Compute node instance.
-        :type  node: :class:`Node`
-
-        :param action: Action to be carried out on the compute node.
-        :type  action: ``str``
-
-        :return: False if an HTTP Bad Request is received, else, True is
-                 returned.
-        :rtype:  ``bool``
-        """
-        compute_node_id = str(node.id)
-
-        compute = ET.Element('COMPUTE')
-
-        compute_id = ET.SubElement(compute, 'ID')
-        compute_id.text = compute_node_id
-
-        state = ET.SubElement(compute, 'STATE')
-        state.text = action
-
-        xml = ET.tostring(compute)
-
-        url = '/compute/%s' % compute_node_id
-        resp = self.connection.request(url, method='PUT',
-                                       data=xml)
-
-        if resp.status == httplib.BAD_REQUEST:
-            return False
-        else:
-            return True
-
-    def _to_images(self, object):
-        """
-        Request a list of images and convert that list to a list of NodeImage
-        objects.
-
-        Request a list of images from the OpenNebula web interface, and
-        issue a request to convert each XML object representation of an image
-        to a NodeImage object.
-
-        :rtype:  ``list`` of :class:`NodeImage`
-        :return: List of images.
-        """
-        images = []
-        for element in object.findall('DISK'):
-            image_id = element.attrib['href'].partition('/storage/')[2]
-            image = self.connection.request(
-                ('/storage/%s' % (image_id))).object
-            images.append(self._to_image(image))
-
-        return images
-
-    def _to_image(self, image):
-        """
-        Take XML object containing an image description and convert to
-        NodeImage object.
-
-        :type  image: :class:`ElementTree`
-        :param image: XML representation of an image.
-
-        :rtype:  :class:`NodeImage`
-        :return: The newly extracted :class:`NodeImage`.
-        """
-        return NodeImage(id=image.findtext('ID'),
-                         name=image.findtext('NAME'),
-                         driver=self.connection.driver,
-                         extra={'size': image.findtext('SIZE'),
-                                'url': image.findtext('URL')})
-
-    def _to_networks(self, object):
-        """
-        Request a list of networks and convert that list to a list of
-        OpenNebulaNetwork objects.
-
-        Request a list of networks from the OpenNebula web interface, and
-        issue a request to convert each XML object representation of a network
-        to an OpenNebulaNetwork object.
-
-        :rtype:  ``list`` of :class:`OpenNebulaNetwork`
-        :return: List of virtual networks.
-        """
-        networks = []
-        for element in object.findall('NETWORK'):
-            network_id = element.attrib['href'].partition('/network/')[2]
-            network_element = self.connection.request(
-                ('/network/%s' % (network_id))).object
-            networks.append(self._to_network(network_element))
-
-        return networks
-
-    def _to_network(self, element):
-        """
-        Take XML object containing a network description and convert to
-        OpenNebulaNetwork object.
-
-        Take XML representation containing a network description and
-        convert to OpenNebulaNetwork object.
-
-        :rtype:  :class:`OpenNebulaNetwork`
-        :return: The newly extracted :class:`OpenNebulaNetwork`.
-        """
-        return OpenNebulaNetwork(id=element.findtext('ID'),
-                                 name=element.findtext('NAME'),
-                                 address=element.findtext('ADDRESS'),
-                                 size=element.findtext('SIZE'),
-                                 driver=self.connection.driver)
-
-    def _to_nodes(self, object):
-        """
-        Request a list of compute nodes and convert that list to a list of
-        Node objects.
-
-        Request a list of compute nodes from the OpenNebula web interface, and
-        issue a request to convert each XML object representation of a node
-        to a Node object.
-
-        :rtype:  ``list`` of :class:`Node`
-        :return: A list of compute nodes.
-        """
-        computes = []
-        for element in object.findall('COMPUTE'):
-            compute_id = element.attrib['href'].partition('/compute/')[2]
-            compute = self.connection.request(
-                ('/compute/%s' % (compute_id))).object
-            computes.append(self._to_node(compute))
-
-        return computes
-
-    def _to_node(self, compute):
-        """
-        Take XML object containing a compute node description and convert to
-        Node object.
-
-        Take XML representation containing a compute node description and
-        convert to Node object.
-
-        :type  compute: :class:`ElementTree`
-        :param compute: XML representation of a compute node.
-
-        :rtype:  :class:`Node`
-        :return: The newly extracted :class:`Node`.
-        """
-        try:
-            state = self.NODE_STATE_MAP[compute.findtext('STATE').upper()]
-        except KeyError:
-            state = NodeState.UNKNOWN
-
-        return Node(id=compute.findtext('ID'),
-                    name=compute.findtext('NAME'),
-                    state=state,
-                    public_ips=self._extract_networks(compute),
-                    private_ips=[],
-                    driver=self.connection.driver,
-                    image=self._extract_images(compute))
-
-    def _extract_networks(self, compute):
-        """
-        Extract networks from a compute node XML representation.
-
-        Extract network descriptions from a compute node XML representation,
-        converting each network to an OpenNebulaNetwork object.
-
-        :type  compute: :class:`ElementTree`
-        :param compute: XML representation of a compute node.
-
-        :rtype:  ``list`` of :class:`OpenNebulaNetwork`s.
-        :return: List of virtual networks attached to the compute node.
-        """
-        networks = list()
-
-        network_list = compute.find('NETWORK')
-        for element in network_list.findall('NIC'):
-            networks.append(
-                OpenNebulaNetwork(id=element.attrib.get('network', None),
-                                  name=None,
-                                  address=element.attrib.get('ip', None),
-                                  size=1,
-                                  driver=self.connection.driver))
-
-        return networks
-
-    def _extract_images(self, compute):
-        """
-        Extract image disks from a compute node XML representation.
-
-        Extract image disk descriptions from a compute node XML representation,
-        converting the disks to an NodeImage object.
-
-        :type  compute: :class:`ElementTree`
-        :param compute: XML representation of a compute node.
-
-        :rtype:  :class:`NodeImage`.
-        :return: First disk attached to a compute node.
-        """
-        disks = list()
-
-        disk_list = compute.find('STORAGE')
-        if disk_list is not None:
-            for element in disk_list.findall('DISK'):
-                disks.append(
-                    NodeImage(id=element.attrib.get('image', None),
-                              name=None,
-                              driver=self.connection.driver,
-                              extra={'dev': element.attrib.get('dev', None)}))
-
-        # @TODO: Return all disks when the Node type accepts multiple
-        # attached disks per node.
-        if len(disks) > 0:
-            return disks[0]
-        else:
-            return None
-
-
-class OpenNebula_1_4_NodeDriver(OpenNebulaNodeDriver):
-    """
-    OpenNebula.org node driver for OpenNebula.org v1.4.
-    """
-
-    name = 'OpenNebula (v1.4)'
-
-
-class OpenNebula_2_0_NodeDriver(OpenNebulaNodeDriver):
-    """
-    OpenNebula.org node driver for OpenNebula.org v2.0 through OpenNebula.org
-    v2.2.
-    """
-
-    name = 'OpenNebula (v2.0 - v2.2)'
-
-    def create_node(self, **kwargs):
-        """
-        Create a new OpenNebula node.
-
-        @inherits: :class:`NodeDriver.create_node`
-
-        :keyword networks: List of virtual networks to which this node should
-                           connect. (optional)
-        :type    networks: :class:`OpenNebulaNetwork` or ``list``
-                           of :class:`OpenNebulaNetwork`
-
-        :keyword context: Custom (key, value) pairs to be injected into
-                          compute node XML description. (optional)
-        :type    context: ``dict``
-
-        :return: Instance of a newly created node.
-        :rtype:  :class:`Node`
-        """
-        compute = ET.Element('COMPUTE')
-
-        name = ET.SubElement(compute, 'NAME')
-        name.text = kwargs['name']
-
-        instance_type = ET.SubElement(compute, 'INSTANCE_TYPE')
-        instance_type.text = kwargs['size'].name
-
-        disk = ET.SubElement(compute, 'DISK')
-        ET.SubElement(disk,
-                      'STORAGE',
-                      {'href': '/storage/%s' % (str(kwargs['image'].id))})
-
-        if 'networks' in kwargs:
-            if not isinstance(kwargs['networks'], list):
-                kwargs['networks'] = [kwargs['networks']]
-
-            for network in kwargs['networks']:
-                nic = ET.SubElement(compute, 'NIC')
-                ET.SubElement(nic, 'NETWORK',
-                              {'href': '/network/%s' % (str(network.id))})
-                if network.address:
-                    ip_line = ET.SubElement(nic, 'IP')
-                    ip_line.text = network.address
-
-        if 'context' in kwargs:
-            if isinstance(kwargs['context'], dict):
-                contextGroup = ET.SubElement(compute, 'CONTEXT')
-                for key, value in list(kwargs['context'].items()):
-                    context = ET.SubElement(contextGroup, key.upper())
-                    context.text = value
-
-        xml = ET.tostring(compute)
-        node = self.connection.request('/compute', method='POST',
-                                       data=xml).object
-
-        return self._to_node(node)
-
-    def destroy_node(self, node):
-        url = '/compute/%s' % (str(node.id))
-        resp = self.connection.request(url, method='DELETE')
-
-        return resp.status == httplib.NO_CONTENT
-
-    def list_sizes(self, location=None):
-        """
-        Return list of sizes on a provider.
-
-        @inherits: :class:`NodeDriver.list_sizes`
-
-        :return: List of compute node sizes supported by the cloud provider.
-        :rtype:  ``list`` of :class:`OpenNebulaNodeSize`
-        """
-        return [
-            OpenNebulaNodeSize(id=1,
-                               name='small',
-                               ram=1024,
-                               cpu=1,
-                               disk=None,
-                               bandwidth=None,
-                               price=None,
-                               driver=self),
-            OpenNebulaNodeSize(id=2,
-                               name='medium',
-                               ram=4096,
-                               cpu=4,
-                               disk=None,
-                               bandwidth=None,
-                               price=None,
-                               driver=self),
-            OpenNebulaNodeSize(id=3,
-                               name='large',
-                               ram=8192,
-                               cpu=8,
-                               disk=None,
-                               bandwidth=None,
-                               price=None,
-                               driver=self),
-            OpenNebulaNodeSize(id=4,
-                               name='custom',
-                               ram=0,
-                               cpu=0,
-                               disk=None,
-                               bandwidth=None,
-                               price=None,
-                               driver=self),
-        ]
-
-    def _to_images(self, object):
-        """
-        Request a list of images and convert that list to a list of NodeImage
-        objects.
-
-        Request a list of images from the OpenNebula web interface, and
-        issue a request to convert each XML object representation of an image
-        to a NodeImage object.
-
-        :rtype:  ``list`` of :class:`NodeImage`
-        :return: List of images.
-        """
-        images = []
-        for element in object.findall('STORAGE'):
-            image_id = element.attrib["href"].partition("/storage/")[2]
-            image = self.connection.request(
-                ("/storage/%s" % (image_id))).object
-            images.append(self._to_image(image))
-
-        return images
-
-    def _to_image(self, image):
-        """
-        Take XML object containing an image description and convert to
-        NodeImage object.
-
-        :type  image: :class:`ElementTree`
-        :param image: XML representation of an image.
-
-        :rtype:  :class:`NodeImage`
-        :return: The newly extracted :class:`NodeImage`.
-        """
-        return NodeImage(id=image.findtext('ID'),
-                         name=image.findtext('NAME'),
-                         driver=self.connection.driver,
-                         extra={'description': image.findtext('DESCRIPTION'),
-                                'type': image.findtext('TYPE'),
-                                'size': image.findtext('SIZE'),
-                                'fstype': image.findtext('FSTYPE', None)})
-
-    def _to_node(self, compute):
-        """
-        Take XML object containing a compute node description and convert to
-        Node object.
-
-        Take XML representation containing a compute node description and
-        convert to Node object.
-
-        :type  compute: :class:`ElementTree`
-        :param compute: XML representation of a compute node.
-
-        :rtype:  :class:`Node`
-        :return: The newly extracted :class:`Node`.
-        """
-        try:
-            state = self.NODE_STATE_MAP[compute.findtext('STATE').upper()]
-        except KeyError:
-            state = NodeState.UNKNOWN
-
-        return Node(id=compute.findtext('ID'),
-                    name=compute.findtext('NAME'),
-                    state=state,
-                    public_ips=self._extract_networks(compute),
-                    private_ips=[],
-                    driver=self.connection.driver,
-                    image=self._extract_images(compute),
-                    size=self._extract_size(compute),
-                    extra={'context': self._extract_context(compute)})
-
-    def _extract_networks(self, compute):
-        """
-        Extract networks from a compute node XML representation.
-
-        Extract network descriptions from a compute node XML representation,
-        converting each network to an OpenNebulaNetwork object.
-
-        :type  compute: :class:`ElementTree`
-        :param compute: XML representation of a compute node.
-
-        :rtype:  ``list`` of :class:`OpenNebulaNetwork`
-        :return: List of virtual networks attached to the compute node.
-        """
-        networks = []
-
-        for element in compute.findall('NIC'):
-            network = element.find('NETWORK')
-            network_id = network.attrib['href'].partition('/network/')[2]
-
-            networks.append(
-                OpenNebulaNetwork(id=network_id,
-                                  name=network.attrib.get('name', None),
-                                  address=element.findtext('IP'),
-                                  size=1,
-                                  driver=self.connection.driver,
-                                  extra={'mac': element.findtext('MAC')}))
-
-        return networks
-
-    def _extract_images(self, compute):
-        """
-        Extract image disks from a compute node XML representation.
-
-        Extract image disk descriptions from a compute node XML representation,
-        converting the disks to an NodeImage object.
-
-        :type  compute: :class:`ElementTree`
-        :param compute: XML representation of a compute node.
-
-        :rtype:  ``list`` of :class:`NodeImage`
-        :return: Disks attached to a compute node.
-        """
-        disks = list()
-
-        for element in compute.findall('DISK'):
-            disk = element.find('STORAGE')
-            image_id = disk.attrib['href'].partition('/storage/')[2]
-
-            if 'id' in element.attrib:
-                disk_id = element.attrib['id']
-            else:
-                disk_id = None
-
-            disks.append(
-                NodeImage(id=image_id,
-                          name=disk.attrib.get('name', None),
-                          driver=self.connection.driver,
-                          extra={'type': element.findtext('TYPE'),
-                                 'disk_id': disk_id,
-                                 'target': element.findtext('TARGET')}))
-
-        # Return all disks when the Node type accepts multiple attached disks
-        # per node.
-        if len(disks) > 1:
-            return disks
-        elif len(disks) == 1:
-            return disks[0]
-        else:
-            return None
-
-    def _extract_size(self, compute):
-        """
-        Extract size, or node type, from a compute node XML representation.
-
-        Extract node size, or node type, description from a compute node XML
-        representation, converting the node size to a NodeSize object.
-
-        :type  compute: :class:`ElementTree`
-        :param compute: XML representation of a compute node.
-
-        :rtype:  :class:`OpenNebulaNodeSize`
-        :return: Node type of compute node.
-        """
-        instance_type = compute.find('INSTANCE_TYPE')
-
-        try:
-            return next((node_size for node_size in self.list_sizes()
-                        if node_size.name == instance_type.text))
-        except StopIteration:
-            return None
-
-    def _extract_context(self, compute):
-        """
-        Extract size, or node type, from a compute node XML representation.
-
-        Extract node size, or node type, description from a compute node XML
-        representation, converting the node size to a NodeSize object.
-
-        :type  compute: :class:`ElementTree`
-        :param compute: XML representation of a compute node.
-
-        :rtype:  ``dict``
-        :return: Dictionary containing (key, value) pairs related to
-                 compute node context.
-        """
-        contexts = dict()
-        context = compute.find('CONTEXT')
-
-        if context is not None:
-            for context_element in list(context):
-                contexts[context_element.tag.lower()] = context_element.text
-
-        return contexts
-
-
-class OpenNebula_3_0_NodeDriver(OpenNebula_2_0_NodeDriver):
-    """
-    OpenNebula.org node driver for OpenNebula.org v3.0.
-    """
-
-    name = 'OpenNebula (v3.0)'
-
-    def ex_node_set_save_name(self, node, name):
-        """
-        Build action representation and instruct node to commit action.
-
-        Build action representation from the compute node ID, the disk image
-        which will be saved, and the name under which the image will be saved
-        upon shutting down the compute node.
-
-        :param node: Compute node instance.
-        :type  node: :class:`Node`
-
-        :param name: Name under which the image should be saved after shutting
-                     down the compute node.
-        :type  name: ``str``
-
-        :return: False if an HTTP Bad Request is received, else, True is
-                 returned.
-        :rtype:  ``bool``
-        """
-        compute_node_id = str(node.id)
-
-        compute = ET.Element('COMPUTE')
-
-        compute_id = ET.SubElement(compute, 'ID')
-        compute_id.text = compute_node_id
-
-        disk = ET.SubElement(compute, 'DISK', {'id': str(node.image.id)})
-
-        ET.SubElement(disk, 'STORAGE',
-                      {'href': '/storage/%s' % (str(node.image.id)),
-                       'name': node.image.name})
-
-        ET.SubElement(disk, 'SAVE_AS', {'name': str(name)})
-
-        xml = ET.tostring(compute)
-
-        url = '/compute/%s' % compute_node_id
-        resp = self.connection.request(url, method='PUT',
-                                       data=xml)
-
-        if resp.status == httplib.BAD_REQUEST:
-            return False
-        else:
-            return True
-
-    def _to_network(self, element):
-        """
-        Take XML object containing a network description and convert to
-        OpenNebulaNetwork object.
-
-        Take XML representation containing a network description and
-        convert to OpenNebulaNetwork object.
-
-        :return: The newly extracted :class:`OpenNebulaNetwork`.
-        :rtype:  :class:`OpenNebulaNetwork`
-        """
-        return OpenNebulaNetwork(id=element.findtext('ID'),
-                                 name=element.findtext('NAME'),
-                                 address=element.findtext('ADDRESS'),
-                                 size=element.findtext('SIZE'),
-                                 driver=self.connection.driver,
-                                 extra={'public': element.findtext('PUBLIC')})
-
-
-class OpenNebula_3_2_NodeDriver(OpenNebula_3_0_NodeDriver):
-    """
-    OpenNebula.org node driver for OpenNebula.org v3.2.
-    """
-
-    name = 'OpenNebula (v3.2)'
-
-    def reboot_node(self, node):
-        return self.ex_node_action(node, ACTION.REBOOT)
-
-    def list_sizes(self, location=None):
-        """
-        Return list of sizes on a provider.
-
-        @inherits: :class:`NodeDriver.list_sizes`
-
-        :return: List of compute node sizes supported by the cloud provider.
-        :rtype:  ``list`` of :class:`OpenNebulaNodeSize`
-        """
-        return self._to_sizes(self.connection.request('/instance_type').object)
-
-    def _to_sizes(self, object):
-        """
-        Request a list of instance types and convert that list to a list of
-        OpenNebulaNodeSize objects.
-
-        Request a list of instance types from the OpenNebula web interface,
-        and issue a request to convert each XML object representation of an
-        instance type to an OpenNebulaNodeSize object.
-
-        :return: List of instance types.
-        :rtype:  ``list`` of :class:`OpenNebulaNodeSize`
-        """
-        sizes = []
-        size_id = 1
-
-        attributes = [('name', str, None), ('ram', int, 'MEMORY'),
-                      ('cpu', float, None), ('vcpu', float, None),
-                      ('disk', str, None), ('bandwidth', float, None),
-                      ('price', float, None)]
-
-        for element in object.findall('INSTANCE_TYPE'):
-            size_kwargs = {'id': size_id, 'driver': self}
-            values = self._get_attributes_values(attributes=attributes,
-                                                 element=element)
-            size_kwargs.update(values)
-
-            size = OpenNebulaNodeSize(**size_kwargs)
-            sizes.append(size)
-            size_id += 1
-
-        return sizes
-
-    def _get_attributes_values(self, attributes, element):
-        values = {}
-
-        for attribute_name, attribute_type, alias in attributes:
-                key = alias if alias else attribute_name.upper()
-                value = element.findtext(key)
-
-                if value is not None:
-                    value = attribute_type(value)
-
-                values[attribute_name] = value
-
-        return values
-
-
-class OpenNebula_3_6_NodeDriver(OpenNebula_3_2_NodeDriver):
-    """
-    OpenNebula.org node driver for OpenNebula.org v3.6.
-    """
-
-    name = 'OpenNebula (v3.6)'
-
-    def create_volume(self, size, name, location=None, snapshot=None):
-        storage = ET.Element('STORAGE')
-
-        vol_name = ET.SubElement(storage, 'NAME')
-        vol_name.text = name
-
-        vol_type = ET.SubElement(storage, 'TYPE')
-        vol_type.text = 'DATABLOCK'
-
-        description = ET.SubElement(storage, 'DESCRIPTION')
-        description.text = 'Attached storage'
-
-        public = ET.SubElement(storage, 'PUBLIC')
-        public.text = 'NO'
-
-        persistent = ET.SubElement(storage, 'PERSISTENT')
-        persistent.text = 'YES'
-
-        fstype = ET.SubElement(storage, 'FSTYPE')
-        fstype.text = 'ext3'
-
-        vol_size = ET.SubElement(storage, 'SIZE')
-        vol_size.text = str(size)
-
-        xml = ET.tostring(storage)
-        volume = self.connection.request('/storage',
-                                         {'occixml': xml},
-                                         method='POST').object
-
-        return self._to_volume(volume)
-
-    def destroy_volume(self, volume):
-        url = '/storage/%s' % (str(volume.id))
-        resp = self.connection.request(url, method='DELETE')
-
-        return resp.status == httplib.NO_CONTENT
-
-    def attach_volume(self, node, volume, device):
-        action = ET.Element('ACTION')
-
-        perform = ET.SubElement(action, 'PERFORM')
-        perform.text = 'ATTACHDISK'
-
-        params = ET.SubElement(action, 'PARAMS')
-
-        ET.SubElement(params,
-                      'STORAGE',
-                      {'href': '/storage/%s' % (str(volume.id))})
-
-        target = ET.SubElement(params, 'TARGET')
-        target.text = device
-
-        xml = ET.tostring(action)
-
-        url = '/compute/%s/action' % node.id
-
-        resp = self.connection.request(url, method='POST', data=xml)
-        return resp.status == httplib.ACCEPTED
-
-    def _do_detach_volume(self, node_id, disk_id):
-        action = ET.Element('ACTION')
-
-        perform = ET.SubElement(action, 'PERFORM')
-        perform.text = 'DETACHDISK'
-
-        params = ET.SubElement(action, 'PARAMS')
-
-        ET.SubElement(params,
-                      'DISK',
-                      {'id': disk_id})
-
-        xml = ET.tostring(action)
-
-        url = '/compute/%s/action' % node_id
-
-        resp = self.connection.request(url, method='POST', data=xml)
-        return resp.status == httplib.ACCEPTED
-
-    def detach_volume(self, volume):
-        # We need to find the node using this volume
-        for node in self.list_nodes():
-            if type(node.image) is not list:
-                # This node has only one associated image. It is not the one we
-                # are after.
-                continue
-
-            for disk in node.image:
-                if disk.id == volume.id:
-                    # Node found. We can now detach the volume
-                    disk_id = disk.extra['disk_id']
-                    return self._do_detach_volume(node.id, disk_id)
-
-        return False
-
-    def list_volumes(self):
-        return self._to_volumes(self.connection.request('/storage').object)
-
-    def _to_volume(self, storage):
-        return StorageVolume(id=storage.findtext('ID'),
-                             name=storage.findtext('NAME'),
-                             size=int(storage.findtext('SIZE')),
-                             driver=self.connection.driver)
-
-    def _to_volumes(self, object):
-        volumes = []
-        for storage in object.findall('STORAGE'):
-            storage_id = storage.attrib['href'].partition('/storage/')[2]
-
-            volumes.append(self._to_volume(
-                self.connection.request('/storage/%s' % storage_id).object))
-
-        return volumes
-
-
-class OpenNebula_3_8_NodeDriver(OpenNebula_3_6_NodeDriver):
-    """
-    OpenNebula.org node driver for OpenNebula.org v3.8.
-    """
-
-    name = 'OpenNebula (v3.8)'
-    plain_auth = API_PLAIN_AUTH
-
-    def _to_sizes(self, object):
-        """
-        Request a list of instance types and convert that list to a list of
-        OpenNebulaNodeSize objects.
-
-        Request a list of instance types from the OpenNebula web interface,
-        and issue a request to convert each XML object representation of an
-        instance type to an OpenNebulaNodeSize object.
-
-        :return: List of instance types.
-        :rtype:  ``list`` of :class:`OpenNebulaNodeSize`
-        """
-        sizes = []
-        size_id = 1
-
-        attributes = [('name', str, None), ('ram', int, 'MEMORY'),
-                      ('cpu', float, None), ('vcpu', float, None),
-                      ('disk', str, None), ('bandwidth', float, None),
-                      ('price', float, None)]
-
-        for element in object.findall('INSTANCE_TYPE'):
-            element = self.connection.request(
-                ('/instance_type/%s') % (element.attrib['name'])).object
-
-            size_kwargs = {'id': size_id, 'driver': self}
-            values = self._get_attributes_values(attributes=attributes,
-                                                 element=element)
-            size_kwargs.update(values)
-
-            size = OpenNebulaNodeSize(**size_kwargs)
-            sizes.append(size)
-            size_id += 1
-        return sizes
-
-    def _ex_connection_class_kwargs(self):
-        """
-        Set plain_auth as an extra :class:`OpenNebulaConnection_3_8` argument
-
-        :return: ``dict`` of :class:`OpenNebulaConnection_3_8` input arguments
-        """
-
-        return {'plain_auth': self.plain_auth}