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:08 UTC

[21/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/openstack.py
----------------------------------------------------------------------
diff --git a/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/openstack.py b/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/openstack.py
deleted file mode 100644
index 1fa3479..0000000
--- a/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/openstack.py
+++ /dev/null
@@ -1,2528 +0,0 @@
-# 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.
-"""
-OpenStack driver
-"""
-from libcloud.utils.iso8601 import parse_date
-
-try:
-    import simplejson as json
-except ImportError:
-    import json
-
-try:
-    from lxml import etree as ET
-except ImportError:
-    from xml.etree import ElementTree as ET
-
-import warnings
-import base64
-
-from libcloud.utils.py3 import httplib
-from libcloud.utils.py3 import b
-from libcloud.utils.py3 import next
-from libcloud.utils.py3 import urlparse
-
-
-from libcloud.common.openstack import OpenStackBaseConnection
-from libcloud.common.openstack import OpenStackDriverMixin
-from libcloud.common.openstack import OpenStackException
-from libcloud.common.openstack import OpenStackResponse
-from libcloud.utils.networking import is_public_subnet
-from libcloud.compute.base import NodeSize, NodeImage
-from libcloud.compute.base import (NodeDriver, Node, NodeLocation,
-                                   StorageVolume, VolumeSnapshot)
-from libcloud.compute.base import KeyPair
-from libcloud.compute.types import NodeState, StorageVolumeState, Provider, \
-    VolumeSnapshotState
-from libcloud.pricing import get_size_price
-from libcloud.utils.xml import findall
-
-__all__ = [
-    'OpenStack_1_0_Response',
-    'OpenStack_1_0_Connection',
-    'OpenStack_1_0_NodeDriver',
-    'OpenStack_1_0_SharedIpGroup',
-    'OpenStack_1_0_NodeIpAddresses',
-    'OpenStack_1_1_Response',
-    'OpenStack_1_1_Connection',
-    'OpenStack_1_1_NodeDriver',
-    'OpenStack_1_1_FloatingIpPool',
-    'OpenStack_1_1_FloatingIpAddress',
-    'OpenStackNodeDriver'
-]
-
-ATOM_NAMESPACE = "http://www.w3.org/2005/Atom"
-
-DEFAULT_API_VERSION = '1.1'
-
-
-class OpenStackComputeConnection(OpenStackBaseConnection):
-    # default config for http://devstack.org/
-    service_type = 'compute'
-    service_name = 'nova'
-    service_region = 'RegionOne'
-
-
-class OpenStackNodeDriver(NodeDriver, OpenStackDriverMixin):
-    """
-    Base OpenStack node driver. Should not be used directly.
-    """
-    api_name = 'openstack'
-    name = 'OpenStack'
-    website = 'http://openstack.org/'
-
-    NODE_STATE_MAP = {
-        'BUILD': NodeState.PENDING,
-        'REBUILD': NodeState.PENDING,
-        'ACTIVE': NodeState.RUNNING,
-        'SUSPENDED': NodeState.STOPPED,
-        'SHUTOFF': NodeState.STOPPED,
-        'DELETED': NodeState.TERMINATED,
-        'QUEUE_RESIZE': NodeState.PENDING,
-        'PREP_RESIZE': NodeState.PENDING,
-        'VERIFY_RESIZE': NodeState.RUNNING,
-        'PASSWORD': NodeState.PENDING,
-        'RESCUE': NodeState.PENDING,
-        'REBOOT': NodeState.REBOOTING,
-        'HARD_REBOOT': NodeState.REBOOTING,
-        'SHARE_IP': NodeState.PENDING,
-        'SHARE_IP_NO_CONFIG': NodeState.PENDING,
-        'DELETE_IP': NodeState.PENDING,
-        'ERROR': NodeState.ERROR,
-        'UNKNOWN': NodeState.UNKNOWN
-    }
-
-    # http://developer.openstack.org/api-ref-blockstorage-v2.html#volumes-v2
-    VOLUME_STATE_MAP = {
-        'creating': StorageVolumeState.CREATING,
-        'available': StorageVolumeState.AVAILABLE,
-        'attaching': StorageVolumeState.ATTACHING,
-        'in-use': StorageVolumeState.INUSE,
-        'deleting': StorageVolumeState.DELETING,
-        'error': StorageVolumeState.ERROR,
-        'error_deleting': StorageVolumeState.ERROR,
-        'backing-up': StorageVolumeState.BACKUP,
-        'restoring-backup': StorageVolumeState.BACKUP,
-        'error_restoring': StorageVolumeState.ERROR,
-        'error_extending': StorageVolumeState.ERROR,
-    }
-
-    # http://developer.openstack.org/api-ref-blockstorage-v2.html#ext-backups-v2
-    SNAPSHOT_STATE_MAP = {
-        'creating': VolumeSnapshotState.CREATING,
-        'available': VolumeSnapshotState.AVAILABLE,
-        'deleting': VolumeSnapshotState.DELETING,
-        'error': VolumeSnapshotState.ERROR,
-        'restoring': VolumeSnapshotState.RESTORING,
-        'error_restoring': VolumeSnapshotState.ERROR
-    }
-
-    def __new__(cls, key, secret=None, secure=True, host=None, port=None,
-                api_version=DEFAULT_API_VERSION, **kwargs):
-        if cls is OpenStackNodeDriver:
-            if api_version == '1.0':
-                cls = OpenStack_1_0_NodeDriver
-            elif api_version == '1.1':
-                cls = OpenStack_1_1_NodeDriver
-            else:
-                raise NotImplementedError(
-                    "No OpenStackNodeDriver found for API version %s" %
-                    (api_version))
-        return super(OpenStackNodeDriver, cls).__new__(cls)
-
-    def __init__(self, *args, **kwargs):
-        OpenStackDriverMixin.__init__(self, **kwargs)
-        super(OpenStackNodeDriver, self).__init__(*args, **kwargs)
-
-    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, ex_all_tenants=False):
-        """
-        List the nodes in a tenant
-
-        :param ex_all_tenants: List nodes for all the tenants. Note: Your user
-                               must have admin privileges for this
-                               functionality to work.
-        :type ex_all_tenants: ``bool``
-        """
-        params = {}
-        if ex_all_tenants:
-            params = {'all_tenants': 1}
-        return self._to_nodes(
-            self.connection.request('/servers/detail', params=params).object)
-
-    def create_volume(self, size, name, location=None, snapshot=None,
-                      ex_volume_type=None):
-        """
-        Create a new volume.
-
-        :param size: Size of volume in gigabytes (required)
-        :type size: ``int``
-
-        :param name: Name of the volume to be created
-        :type name: ``str``
-
-        :param location: Which data center to create a volume in. If
-                               empty, undefined behavior will be selected.
-                               (optional)
-        :type location: :class:`.NodeLocation`
-
-        :param snapshot:  Snapshot from which to create the new
-                          volume.  (optional)
-        :type snapshot:  :class:`.VolumeSnapshot`
-
-        :param ex_volume_type: What kind of volume to create.
-                            (optional)
-        :type ex_volume_type: ``str``
-
-        :return: The newly created volume.
-        :rtype: :class:`StorageVolume`
-        """
-        volume = {
-            'display_name': name,
-            'display_description': name,
-            'size': size,
-            'volume_type': ex_volume_type,
-            'metadata': {
-                'contents': name,
-            },
-            'availability_zone': location
-        }
-
-        if snapshot:
-            volume['snapshot_id'] = snapshot.id
-
-        resp = self.connection.request('/os-volumes',
-                                       method='POST',
-                                       data={'volume': volume})
-        return self._to_volume(resp.object)
-
-    def destroy_volume(self, volume):
-        return self.connection.request('/os-volumes/%s' % volume.id,
-                                       method='DELETE').success()
-
-    def attach_volume(self, node, volume, device="auto"):
-        # when "auto" or None is provided for device, openstack will let
-        # the guest OS pick the next available device (fi. /dev/vdb)
-        return self.connection.request(
-            '/servers/%s/os-volume_attachments' % node.id,
-            method='POST',
-            data={
-                'volumeAttachment': {
-                    'volumeId': volume.id,
-                    'device': device,
-                }
-            }).success()
-
-    def detach_volume(self, volume, ex_node=None):
-        # when ex_node is not provided, volume is detached from all nodes
-        failed_nodes = []
-        for attachment in volume.extra['attachments']:
-            if not ex_node or ex_node.id == attachment['serverId']:
-                response = self.connection.request(
-                    '/servers/%s/os-volume_attachments/%s' %
-                    (attachment['serverId'], attachment['id']),
-                    method='DELETE')
-
-                if not response.success():
-                    failed_nodes.append(attachment['serverId'])
-        if failed_nodes:
-            raise OpenStackException(
-                'detach_volume failed for nodes with id: %s' %
-                ', '.join(failed_nodes), 500, self
-            )
-        return True
-
-    def list_volumes(self):
-        return self._to_volumes(
-            self.connection.request('/os-volumes').object)
-
-    def ex_get_volume(self, volumeId):
-        return self._to_volume(
-            self.connection.request('/os-volumes/%s' % volumeId).object)
-
-    def list_images(self, location=None, ex_only_active=True):
-        """
-        Lists all active images
-
-        @inherits: :class:`NodeDriver.list_images`
-
-        :param ex_only_active: True if list only active
-        :type ex_only_active: ``bool``
-
-        """
-        return self._to_images(
-            self.connection.request('/images/detail').object, ex_only_active)
-
-    def get_image(self, image_id):
-        """
-        Get an image based on an image_id
-
-        @inherits: :class:`NodeDriver.get_image`
-
-        :param image_id: Image identifier
-        :type image_id: ``str``
-
-        :return: A NodeImage object
-        :rtype: :class:`NodeImage`
-
-        """
-        return self._to_image(self.connection.request(
-            '/images/%s' % (image_id,)).object['image'])
-
-    def list_sizes(self, location=None):
-        return self._to_sizes(
-            self.connection.request('/flavors/detail').object)
-
-    def list_locations(self):
-        return [NodeLocation(0, '', '', self)]
-
-    def _ex_connection_class_kwargs(self):
-        return self.openstack_connection_kwargs()
-
-    def ex_get_node_details(self, node_id):
-        """
-        Lists details of the specified server.
-
-        :param       node_id: ID of the node which should be used
-        :type        node_id: ``str``
-
-        :rtype: :class:`Node`
-        """
-        # @TODO: Remove this if in 0.6
-        if isinstance(node_id, Node):
-            node_id = node_id.id
-
-        uri = '/servers/%s' % (node_id)
-        resp = self.connection.request(uri, method='GET')
-        if resp.status == httplib.NOT_FOUND:
-            return None
-
-        return self._to_node_from_obj(resp.object)
-
-    def ex_soft_reboot_node(self, node):
-        """
-        Soft reboots the specified server
-
-        :param      node:  node
-        :type       node: :class:`Node`
-
-        :rtype: ``bool``
-        """
-        return self._reboot_node(node, reboot_type='SOFT')
-
-    def ex_hard_reboot_node(self, node):
-        """
-        Hard reboots the specified server
-
-        :param      node:  node
-        :type       node: :class:`Node`
-
-        :rtype: ``bool``
-        """
-        return self._reboot_node(node, reboot_type='HARD')
-
-
-class OpenStackNodeSize(NodeSize):
-    """
-    NodeSize class for the OpenStack.org driver.
-
-    Following the example of OpenNebula.org driver
-    and following guidelines:
-    https://issues.apache.org/jira/browse/LIBCLOUD-119
-    """
-
-    def __init__(self, id, name, ram, disk, bandwidth, price, driver,
-                 vcpus=None, ephemeral_disk=None, swap=None, extra=None):
-        super(OpenStackNodeSize, self).__init__(id=id, name=name, ram=ram,
-                                                disk=disk,
-                                                bandwidth=bandwidth,
-                                                price=price, driver=driver)
-        self.vcpus = vcpus
-        self.ephemeral_disk = ephemeral_disk
-        self.swap = swap
-        self.extra = extra
-
-    def __repr__(self):
-        return (('<OpenStackNodeSize: id=%s, name=%s, ram=%s, disk=%s, '
-                 'bandwidth=%s, price=%s, driver=%s, vcpus=%s,  ...>')
-                % (self.id, self.name, self.ram, self.disk, self.bandwidth,
-                   self.price, self.driver.name, self.vcpus))
-
-
-class OpenStack_1_0_Response(OpenStackResponse):
-    def __init__(self, *args, **kwargs):
-        # done because of a circular reference from
-        # NodeDriver -> Connection -> Response
-        self.node_driver = OpenStack_1_0_NodeDriver
-        super(OpenStack_1_0_Response, self).__init__(*args, **kwargs)
-
-
-class OpenStack_1_0_Connection(OpenStackComputeConnection):
-    responseCls = OpenStack_1_0_Response
-    default_content_type = 'application/xml; charset=UTF-8'
-    accept_format = 'application/xml'
-    XML_NAMESPACE = 'http://docs.rackspacecloud.com/servers/api/v1.0'
-
-
-class OpenStack_1_0_NodeDriver(OpenStackNodeDriver):
-    """
-    OpenStack node driver.
-
-    Extra node attributes:
-        - password: root password, available after create.
-        - hostId: represents the host your cloud server runs on
-        - imageId: id of image
-        - flavorId: id of flavor
-    """
-    connectionCls = OpenStack_1_0_Connection
-    type = Provider.OPENSTACK
-
-    features = {'create_node': ['generates_password']}
-
-    def __init__(self, *args, **kwargs):
-        self._ex_force_api_version = str(kwargs.pop('ex_force_api_version',
-                                                    None))
-        self.XML_NAMESPACE = self.connectionCls.XML_NAMESPACE
-        super(OpenStack_1_0_NodeDriver, self).__init__(*args, **kwargs)
-
-    def _to_images(self, object, ex_only_active):
-        images = []
-        for image in findall(object, 'image', self.XML_NAMESPACE):
-            if ex_only_active and image.get('status') != 'ACTIVE':
-                continue
-            images.append(self._to_image(image))
-
-        return images
-
-    def _to_image(self, element):
-        return NodeImage(id=element.get('id'),
-                         name=element.get('name'),
-                         driver=self.connection.driver,
-                         extra={'updated': element.get('updated'),
-                                'created': element.get('created'),
-                                'status': element.get('status'),
-                                'serverId': element.get('serverId'),
-                                'progress': element.get('progress'),
-                                'minDisk': element.get('minDisk'),
-                                'minRam': element.get('minRam')
-                                }
-                         )
-
-    def _change_password_or_name(self, node, name=None, password=None):
-        uri = '/servers/%s' % (node.id)
-
-        if not name:
-            name = node.name
-
-        body = {'xmlns': self.XML_NAMESPACE,
-                'name': name}
-
-        if password is not None:
-            body['adminPass'] = password
-
-        server_elm = ET.Element('server', body)
-
-        resp = self.connection.request(
-            uri, method='PUT', data=ET.tostring(server_elm))
-
-        if resp.status == httplib.NO_CONTENT and password is not None:
-            node.extra['password'] = password
-
-        return resp.status == httplib.NO_CONTENT
-
-    def create_node(self, **kwargs):
-        """
-        Create a new node
-
-        @inherits: :class:`NodeDriver.create_node`
-
-        :keyword    ex_metadata: Key/Value metadata to associate with a node
-        :type       ex_metadata: ``dict``
-
-        :keyword    ex_files:   File Path => File contents to create on
-                                the node
-        :type       ex_files:   ``dict``
-
-        :keyword    ex_shared_ip_group_id: The server is launched into
-            that shared IP group
-        :type       ex_shared_ip_group_id: ``str``
-        """
-        name = kwargs['name']
-        image = kwargs['image']
-        size = kwargs['size']
-
-        attributes = {'xmlns': self.XML_NAMESPACE,
-                      'name': name,
-                      'imageId': str(image.id),
-                      'flavorId': str(size.id)}
-
-        if 'ex_shared_ip_group' in kwargs:
-            # Deprecate this. Be explicit and call the variable
-            # ex_shared_ip_group_id since user needs to pass in the id, not the
-            # name.
-            warnings.warn('ex_shared_ip_group argument is deprecated.'
-                          ' Please use ex_shared_ip_group_id')
-
-        if 'ex_shared_ip_group_id' in kwargs:
-            shared_ip_group_id = kwargs['ex_shared_ip_group_id']
-            attributes['sharedIpGroupId'] = shared_ip_group_id
-
-        server_elm = ET.Element('server', attributes)
-
-        metadata_elm = self._metadata_to_xml(kwargs.get("ex_metadata", {}))
-        if metadata_elm:
-            server_elm.append(metadata_elm)
-
-        files_elm = self._files_to_xml(kwargs.get("ex_files", {}))
-        if files_elm:
-            server_elm.append(files_elm)
-
-        resp = self.connection.request("/servers",
-                                       method='POST',
-                                       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.
-
-        :class:`Node.extra['password']` will be set to the new value if the
-        operation was successful.
-
-        :param      node: node to set password
-        :type       node: :class:`Node`
-
-        :param      password: new password.
-        :type       password: ``str``
-
-        :rtype: ``bool``
-        """
-        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.
-
-        :param      node: node to set name
-        :type       node: :class:`Node`
-
-        :param      name: new name
-        :type       name: ``str``
-
-        :rtype: ``bool``
-        """
-        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.
-
-        :param      node: node to resize.
-        :type       node: :class:`Node`
-
-        :param      size: new size.
-        :type       size: :class:`NodeSize`
-
-        :rtype: ``bool``
-        """
-        elm = ET.Element(
-            '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 == httplib.ACCEPTED
-
-    def ex_confirm_resize(self, node):
-        """
-        Confirm a resize request which is currently in progress. If a resize
-        request is not explicitly confirmed or reverted it's automatically
-        confirmed after 24 hours.
-
-        For more info refer to the API documentation: http://goo.gl/zjFI1
-
-        :param      node: node for which the resize request will be confirmed.
-        :type       node: :class:`Node`
-
-        :rtype: ``bool``
-        """
-        elm = ET.Element(
-            'confirmResize',
-            {'xmlns': self.XML_NAMESPACE},
-        )
-
-        resp = self.connection.request("/servers/%s/action" % (node.id),
-                                       method='POST',
-                                       data=ET.tostring(elm))
-        return resp.status == httplib.NO_CONTENT
-
-    def ex_revert_resize(self, node):
-        """
-        Revert a resize request which is currently in progress.
-        All resizes are automatically confirmed after 24 hours if they have
-        not already been confirmed explicitly or reverted.
-
-        For more info refer to the API documentation: http://goo.gl/AizBu
-
-        :param      node: node for which the resize request will be reverted.
-        :type       node: :class:`Node`
-
-        :rtype: ``bool``
-        """
-        elm = ET.Element(
-            'revertResize',
-            {'xmlns': self.XML_NAMESPACE}
-        )
-
-        resp = self.connection.request("/servers/%s/action" % (node.id),
-                                       method='POST',
-                                       data=ET.tostring(elm))
-        return resp.status == httplib.NO_CONTENT
-
-    def ex_rebuild(self, node_id, image_id):
-        """
-        Rebuilds the specified server.
-
-        :param       node_id: ID of the node which should be used
-        :type        node_id: ``str``
-
-        :param       image_id: ID of the image which should be used
-        :type        image_id: ``str``
-
-        :rtype: ``bool``
-        """
-        # @TODO: Remove those ifs in 0.6
-        if isinstance(node_id, Node):
-            node_id = node_id.id
-
-        if isinstance(image_id, NodeImage):
-            image_id = image_id.id
-
-        elm = ET.Element(
-            '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 == httplib.ACCEPTED
-
-    def ex_create_ip_group(self, group_name, node_id=None):
-        """
-        Creates a shared IP group.
-
-        :param       group_name:  group name which should be used
-        :type        group_name: ``str``
-
-        :param       node_id: ID of the node which should be used
-        :type        node_id: ``str``
-
-        :rtype: ``bool``
-        """
-        # @TODO: Remove this if in 0.6
-        if isinstance(node_id, Node):
-            node_id = node_id.id
-
-        group_elm = ET.Element(
-            'sharedIpGroup',
-            {'xmlns': self.XML_NAMESPACE,
-             'name': group_name}
-        )
-
-        if node_id:
-            ET.SubElement(
-                group_elm,
-                'server',
-                {'id': node_id}
-            )
-
-        resp = self.connection.request('/shared_ip_groups',
-                                       method='POST',
-                                       data=ET.tostring(group_elm))
-        return self._to_shared_ip_group(resp.object)
-
-    def ex_list_ip_groups(self, details=False):
-        """
-        Lists IDs and names for shared IP groups.
-        If details lists all details for shared IP groups.
-
-        :param       details: True if details is required
-        :type        details: ``bool``
-
-        :rtype: ``list`` of :class:`OpenStack_1_0_SharedIpGroup`
-        """
-        uri = '/shared_ip_groups/detail' if details else '/shared_ip_groups'
-        resp = self.connection.request(uri,
-                                       method='GET')
-        groups = findall(resp.object, 'sharedIpGroup',
-                         self.XML_NAMESPACE)
-        return [self._to_shared_ip_group(el) for el in groups]
-
-    def ex_delete_ip_group(self, group_id):
-        """
-        Deletes the specified shared IP group.
-
-        :param       group_id:  group id which should be used
-        :type        group_id: ``str``
-
-        :rtype: ``bool``
-        """
-        uri = '/shared_ip_groups/%s' % group_id
-        resp = self.connection.request(uri, method='DELETE')
-        return resp.status == httplib.NO_CONTENT
-
-    def ex_share_ip(self, group_id, node_id, ip, configure_node=True):
-        """
-        Shares an IP address to the specified server.
-
-        :param       group_id:  group id which should be used
-        :type        group_id: ``str``
-
-        :param       node_id: ID of the node which should be used
-        :type        node_id: ``str``
-
-        :param       ip: ip which should be used
-        :type        ip: ``str``
-
-        :param       configure_node: configure node
-        :type        configure_node: ``bool``
-
-        :rtype: ``bool``
-        """
-        # @TODO: Remove this if in 0.6
-        if isinstance(node_id, Node):
-            node_id = node_id.id
-
-        if configure_node:
-            str_configure = 'true'
-        else:
-            str_configure = 'false'
-
-        elm = ET.Element(
-            'shareIp',
-            {'xmlns': self.XML_NAMESPACE,
-             'sharedIpGroupId': group_id,
-             'configureServer': str_configure},
-        )
-
-        uri = '/servers/%s/ips/public/%s' % (node_id, ip)
-
-        resp = self.connection.request(uri,
-                                       method='PUT',
-                                       data=ET.tostring(elm))
-        return resp.status == httplib.ACCEPTED
-
-    def ex_unshare_ip(self, node_id, ip):
-        """
-        Removes a shared IP address from the specified server.
-
-        :param       node_id: ID of the node which should be used
-        :type        node_id: ``str``
-
-        :param       ip: ip which should be used
-        :type        ip: ``str``
-
-        :rtype: ``bool``
-        """
-        # @TODO: Remove this if in 0.6
-        if isinstance(node_id, Node):
-            node_id = node_id.id
-
-        uri = '/servers/%s/ips/public/%s' % (node_id, ip)
-
-        resp = self.connection.request(uri,
-                                       method='DELETE')
-        return resp.status == httplib.ACCEPTED
-
-    def ex_list_ip_addresses(self, node_id):
-        """
-        List all server addresses.
-
-        :param       node_id: ID of the node which should be used
-        :type        node_id: ``str``
-
-        :rtype: :class:`OpenStack_1_0_NodeIpAddresses`
-        """
-        # @TODO: Remove this if in 0.6
-        if isinstance(node_id, Node):
-            node_id = node_id.id
-
-        uri = '/servers/%s/ips' % node_id
-        resp = self.connection.request(uri,
-                                       method='GET')
-        return self._to_ip_addresses(resp.object)
-
-    def _metadata_to_xml(self, metadata):
-        if len(metadata) == 0:
-            return None
-
-        metadata_elm = ET.Element('metadata')
-        for k, v in list(metadata.items()):
-            meta_elm = ET.SubElement(metadata_elm, 'meta', {'key': str(k)})
-            meta_elm.text = str(v)
-
-        return metadata_elm
-
-    def _files_to_xml(self, files):
-        if len(files) == 0:
-            return None
-
-        personality_elm = ET.Element('personality')
-        for k, v in list(files.items()):
-            file_elm = ET.SubElement(personality_elm,
-                                     'file',
-                                     {'path': str(k)})
-            file_elm.text = base64.b64encode(b(v))
-
-        return personality_elm
-
-    def _reboot_node(self, node, reboot_type='SOFT'):
-        resp = self._node_action(node, ['reboot', ('type', reboot_type)])
-        return resp.status == httplib.ACCEPTED
-
-    def _node_action(self, node, body):
-        if isinstance(body, list):
-            attr = ' '.join(['%s="%s"' % (item[0], item[1])
-                             for item in body[1:]])
-            body = '<%s xmlns="%s" %s/>' % (body[0], self.XML_NAMESPACE, attr)
-        uri = '/servers/%s/action' % (node.id)
-        resp = self.connection.request(uri, method='POST', data=body)
-        return resp
-
-    def _to_nodes(self, object):
-        node_elements = findall(object, 'server', self.XML_NAMESPACE)
-        return [self._to_node(el) for el in node_elements]
-
-    def _to_node_from_obj(self, obj):
-        return self._to_node(findall(obj, 'server', self.XML_NAMESPACE)[0])
-
-    def _to_node(self, el):
-        def get_ips(el):
-            return [ip.get('addr') for ip in el]
-
-        def get_meta_dict(el):
-            d = {}
-            for meta in el:
-                d[meta.get('key')] = meta.text
-            return d
-
-        public_ip = get_ips(findall(el, 'addresses/public/ip',
-                                    self.XML_NAMESPACE))
-        private_ip = get_ips(findall(el, 'addresses/private/ip',
-                                     self.XML_NAMESPACE))
-        metadata = get_meta_dict(findall(el, 'metadata/meta',
-                                         self.XML_NAMESPACE))
-
-        n = Node(id=el.get('id'),
-                 name=el.get('name'),
-                 state=self.NODE_STATE_MAP.get(
-                     el.get('status'), NodeState.UNKNOWN),
-                 public_ips=public_ip,
-                 private_ips=private_ip,
-                 driver=self.connection.driver,
-                 extra={
-                     'password': el.get('adminPass'),
-                     'hostId': el.get('hostId'),
-                     'imageId': el.get('imageId'),
-                     'flavorId': el.get('flavorId'),
-                     'uri': "https://%s%s/servers/%s" % (
-                         self.connection.host,
-                         self.connection.request_path, el.get('id')),
-                     'service_name': self.connection.get_service_name(),
-                     'metadata': metadata})
-        return n
-
-    def _to_sizes(self, object):
-        elements = findall(object, 'flavor', self.XML_NAMESPACE)
-        return [self._to_size(el) for el in elements]
-
-    def _to_size(self, el):
-        vcpus = int(el.get('vcpus')) if el.get('vcpus', None) else None
-        return OpenStackNodeSize(id=el.get('id'),
-                                 name=el.get('name'),
-                                 ram=int(el.get('ram')),
-                                 disk=int(el.get('disk')),
-                                 # XXX: needs hardcode
-                                 vcpus=vcpus,
-                                 bandwidth=None,
-                                 # Hardcoded
-                                 price=self._get_size_price(el.get('id')),
-                                 driver=self.connection.driver)
-
-    def ex_limits(self):
-        """
-        Extra call to get account's limits, such as
-        rates (for example amount of POST requests per day)
-        and absolute limits like total amount of available
-        RAM to be used by servers.
-
-        :return: dict with keys 'rate' and 'absolute'
-        :rtype: ``dict``
-        """
-
-        def _to_rate(el):
-            rate = {}
-            for item in list(el.items()):
-                rate[item[0]] = item[1]
-
-            return rate
-
-        def _to_absolute(el):
-            return {el.get('name'): el.get('value')}
-
-        limits = self.connection.request("/limits").object
-        rate = [_to_rate(el) for el in findall(limits, 'rate/limit',
-                                               self.XML_NAMESPACE)]
-        absolute = {}
-        for item in findall(limits, 'absolute/limit',
-                            self.XML_NAMESPACE):
-            absolute.update(_to_absolute(item))
-
-        return {"rate": rate, "absolute": absolute}
-
-    def create_image(self, node, name, description=None, reboot=True):
-        """Create an image for node.
-
-        @inherits: :class:`NodeDriver.create_image`
-
-        :param      node: node to use as a base for image
-        :type       node: :class:`Node`
-
-        :param      name: name for new image
-        :type       name: ``str``
-
-        :rtype: :class:`NodeImage`
-        """
-
-        image_elm = ET.Element(
-            'image',
-            {'xmlns': self.XML_NAMESPACE,
-             'name': name,
-             'serverId': node.id}
-        )
-
-        return self._to_image(
-            self.connection.request("/images", method="POST",
-                                    data=ET.tostring(image_elm)).object)
-
-    def delete_image(self, image):
-        """Delete an image for node.
-
-        @inherits: :class:`NodeDriver.delete_image`
-
-        :param      image: the image to be deleted
-        :type       image: :class:`NodeImage`
-
-        :rtype: ``bool``
-        """
-        uri = '/images/%s' % image.id
-        resp = self.connection.request(uri, method='DELETE')
-        return resp.status == httplib.NO_CONTENT
-
-    def _to_shared_ip_group(self, el):
-        servers_el = findall(el, 'servers', self.XML_NAMESPACE)
-        if servers_el:
-            servers = [s.get('id')
-                       for s in findall(servers_el[0], 'server',
-                                        self.XML_NAMESPACE)]
-        else:
-            servers = None
-        return OpenStack_1_0_SharedIpGroup(id=el.get('id'),
-                                           name=el.get('name'),
-                                           servers=servers)
-
-    def _to_ip_addresses(self, el):
-        public_ips = [ip.get('addr') for ip in findall(
-            findall(el, 'public', self.XML_NAMESPACE)[0],
-            'ip', self.XML_NAMESPACE)]
-        private_ips = [ip.get('addr') for ip in findall(
-            findall(el, 'private', self.XML_NAMESPACE)[0],
-            'ip', self.XML_NAMESPACE)]
-
-        return OpenStack_1_0_NodeIpAddresses(public_ips, private_ips)
-
-    def _get_size_price(self, size_id):
-        try:
-            return get_size_price(driver_type='compute',
-                                  driver_name=self.api_name,
-                                  size_id=size_id)
-        except KeyError:
-            return 0.0
-
-
-class OpenStack_1_0_SharedIpGroup(object):
-    """
-    Shared IP group info.
-    """
-
-    def __init__(self, id, name, servers=None):
-        self.id = str(id)
-        self.name = name
-        self.servers = servers
-
-
-class OpenStack_1_0_NodeIpAddresses(object):
-    """
-    List of public and private IP addresses of a Node.
-    """
-
-    def __init__(self, public_addresses, private_addresses):
-        self.public_addresses = public_addresses
-        self.private_addresses = private_addresses
-
-
-class OpenStack_1_1_Response(OpenStackResponse):
-    def __init__(self, *args, **kwargs):
-        # done because of a circular reference from
-        # NodeDriver -> Connection -> Response
-        self.node_driver = OpenStack_1_1_NodeDriver
-        super(OpenStack_1_1_Response, self).__init__(*args, **kwargs)
-
-
-class OpenStackNetwork(object):
-    """
-    A Virtual Network.
-    """
-
-    def __init__(self, id, name, cidr, driver, extra=None):
-        self.id = str(id)
-        self.name = name
-        self.cidr = cidr
-        self.driver = driver
-        self.extra = extra or {}
-
-    def __repr__(self):
-        return '<OpenStackNetwork id="%s" name="%s" cidr="%s">' % (self.id,
-                                                                   self.name,
-                                                                   self.cidr,)
-
-
-class OpenStackSecurityGroup(object):
-    """
-    A Security Group.
-    """
-
-    def __init__(self, id, tenant_id, name, description, driver, rules=None,
-                 extra=None):
-        """
-        Constructor.
-
-        :keyword    id: Group id.
-        :type       id: ``str``
-
-        :keyword    tenant_id: Owner of the security group.
-        :type       tenant_id: ``str``
-
-        :keyword    name: Human-readable name for the security group. Might
-                          not be unique.
-        :type       name: ``str``
-
-        :keyword    description: Human-readable description of a security
-                                 group.
-        :type       description: ``str``
-
-        :keyword    rules: Rules associated with this group.
-        :type       rules: ``list`` of
-                    :class:`OpenStackSecurityGroupRule`
-
-        :keyword    extra: Extra attributes associated with this group.
-        :type       extra: ``dict``
-        """
-        self.id = id
-        self.tenant_id = tenant_id
-        self.name = name
-        self.description = description
-        self.driver = driver
-        self.rules = rules or []
-        self.extra = extra or {}
-
-    def __repr__(self):
-        return ('<OpenStackSecurityGroup id=%s tenant_id=%s name=%s \
-        description=%s>' % (self.id, self.tenant_id, self.name,
-                            self.description))
-
-
-class OpenStackSecurityGroupRule(object):
-    """
-    A Rule of a Security Group.
-    """
-
-    def __init__(self, id, parent_group_id, ip_protocol, from_port, to_port,
-                 driver, ip_range=None, group=None, tenant_id=None,
-                 extra=None):
-        """
-        Constructor.
-
-        :keyword    id: Rule id.
-        :type       id: ``str``
-
-        :keyword    parent_group_id: ID of the parent security group.
-        :type       parent_group_id: ``str``
-
-        :keyword    ip_protocol: IP Protocol (icmp, tcp, udp, etc).
-        :type       ip_protocol: ``str``
-
-        :keyword    from_port: Port at start of range.
-        :type       from_port: ``int``
-
-        :keyword    to_port: Port at end of range.
-        :type       to_port: ``int``
-
-        :keyword    ip_range: CIDR for address range.
-        :type       ip_range: ``str``
-
-        :keyword    group: Name of a source security group to apply to rule.
-        :type       group: ``str``
-
-        :keyword    tenant_id: Owner of the security group.
-        :type       tenant_id: ``str``
-
-        :keyword    extra: Extra attributes associated with this rule.
-        :type       extra: ``dict``
-        """
-        self.id = id
-        self.parent_group_id = parent_group_id
-        self.ip_protocol = ip_protocol
-        self.from_port = from_port
-        self.to_port = to_port
-        self.driver = driver
-        self.ip_range = ''
-        self.group = {}
-
-        if group is None:
-            self.ip_range = ip_range
-        else:
-            self.group = {'name': group, 'tenant_id': tenant_id}
-
-        self.tenant_id = tenant_id
-        self.extra = extra or {}
-
-    def __repr__(self):
-        return ('<OpenStackSecurityGroupRule id=%s parent_group_id=%s \
-                ip_protocol=%s from_port=%s to_port=%s>' % (self.id,
-                self.parent_group_id, self.ip_protocol, self.from_port,
-                self.to_port))
-
-
-class OpenStackKeyPair(object):
-    """
-    A KeyPair.
-    """
-
-    def __init__(self, name, fingerprint, public_key, driver, private_key=None,
-                 extra=None):
-        """
-        Constructor.
-
-        :keyword    name: Name of the KeyPair.
-        :type       name: ``str``
-
-        :keyword    fingerprint: Fingerprint of the KeyPair
-        :type       fingerprint: ``str``
-
-        :keyword    public_key: Public key in OpenSSH format.
-        :type       public_key: ``str``
-
-        :keyword    private_key: Private key in PEM format.
-        :type       private_key: ``str``
-
-        :keyword    extra: Extra attributes associated with this KeyPair.
-        :type       extra: ``dict``
-        """
-        self.name = name
-        self.fingerprint = fingerprint
-        self.public_key = public_key
-        self.private_key = private_key
-        self.driver = driver
-        self.extra = extra or {}
-
-    def __repr__(self):
-        return ('<OpenStackKeyPair name=%s fingerprint=%s public_key=%s ...>'
-                % (self.name, self.fingerprint, self.public_key))
-
-
-class OpenStack_1_1_Connection(OpenStackComputeConnection):
-    responseCls = OpenStack_1_1_Response
-    accept_format = 'application/json'
-    default_content_type = 'application/json; charset=UTF-8'
-
-    def encode_data(self, data):
-        return json.dumps(data)
-
-
-class OpenStack_1_1_NodeDriver(OpenStackNodeDriver):
-    """
-    OpenStack node driver.
-    """
-    connectionCls = OpenStack_1_1_Connection
-    type = Provider.OPENSTACK
-
-    features = {"create_node": ["generates_password"]}
-    _networks_url_prefix = '/os-networks'
-
-    def __init__(self, *args, **kwargs):
-        self._ex_force_api_version = str(kwargs.pop('ex_force_api_version',
-                                                    None))
-        super(OpenStack_1_1_NodeDriver, self).__init__(*args, **kwargs)
-
-    def create_node(self, **kwargs):
-        """Create a new node
-
-        @inherits:  :class:`NodeDriver.create_node`
-
-        :keyword    ex_keyname:  The name of the key pair
-        :type       ex_keyname:  ``str``
-
-        :keyword    ex_userdata: String containing user data
-                                 see
-                                 https://help.ubuntu.com/community/CloudInit
-        :type       ex_userdata: ``str``
-
-        :keyword    ex_config_drive: Enable config drive
-                                     see
-                                     http://docs.openstack.org/grizzly/openstack-compute/admin/content/config-drive.html
-        :type       ex_config_drive: ``bool``
-
-        :keyword    ex_security_groups: List of security groups to assign to
-                                        the node
-        :type       ex_security_groups: ``list`` of
-                                       :class:`OpenStackSecurityGroup`
-
-        :keyword    ex_metadata: Key/Value metadata to associate with a node
-        :type       ex_metadata: ``dict``
-
-        :keyword    ex_files:   File Path => File contents to create on
-                                the no  de
-        :type       ex_files:   ``dict``
-
-
-        :keyword    networks: The server is launched into a set of Networks.
-        :type       networks: ``list`` of :class:`OpenStackNetwork`
-
-        :keyword    ex_disk_config: Name of the disk configuration.
-                                    Can be either ``AUTO`` or ``MANUAL``.
-        :type       ex_disk_config: ``str``
-
-        :keyword    ex_config_drive: If True enables metadata injection in a
-                                     server through a configuration drive.
-        :type       ex_config_drive: ``bool``
-
-        :keyword    ex_admin_pass: The root password for the node
-        :type       ex_admin_pass: ``str``
-
-        :keyword    ex_availability_zone: Nova availability zone for the node
-        :type       ex_availability_zone: ``str``
-        """
-
-        server_params = self._create_args_to_params(None, **kwargs)
-
-        resp = self.connection.request("/servers",
-                                       method='POST',
-                                       data={'server': server_params})
-
-        create_response = resp.object['server']
-        server_resp = self.connection.request(
-            '/servers/%s' % create_response['id'])
-        server_object = server_resp.object['server']
-
-        # adminPass is not always present
-        # http://docs.openstack.org/essex/openstack-compute/admin/
-        # content/configuring-compute-API.html#d6e1833
-        server_object['adminPass'] = create_response.get('adminPass', None)
-
-        return self._to_node(server_object)
-
-    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):
-        server = api_image.get('server', {})
-        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'),
-                serverId=server.get('id'),
-                minDisk=api_image.get('minDisk'),
-                minRam=api_image.get('minRam'),
-            )
-        )
-
-    def _to_nodes(self, obj):
-        servers = obj['servers']
-        return [self._to_node(server) for server in servers]
-
-    def _to_volumes(self, obj):
-        volumes = obj['volumes']
-        return [self._to_volume(volume) for volume in volumes]
-
-    def _to_snapshots(self, obj):
-        snapshots = obj['snapshots']
-        return [self._to_snapshot(snapshot) for snapshot in snapshots]
-
-    def _to_sizes(self, obj):
-        flavors = obj['flavors']
-        return [self._to_size(flavor) for flavor in flavors]
-
-    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 'ex_availability_zone' in kwargs:
-            server_params['availability_zone'] = kwargs['ex_availability_zone']
-
-        if 'ex_keyname' in kwargs:
-            server_params['key_name'] = kwargs['ex_keyname']
-
-        if 'ex_userdata' in kwargs:
-            server_params['user_data'] = base64.b64encode(
-                b(kwargs['ex_userdata'])).decode('ascii')
-
-        if 'ex_config_drive' in kwargs:
-            server_params['config_drive'] = kwargs['ex_config_drive']
-
-        if 'ex_disk_config' in kwargs:
-            server_params['OS-DCF:diskConfig'] = kwargs['ex_disk_config']
-
-        if 'ex_config_drive' in kwargs:
-            server_params['config_drive'] = str(kwargs['ex_config_drive'])
-
-        if 'ex_admin_pass' in kwargs:
-            server_params['adminPass'] = kwargs['ex_admin_pass']
-
-        if 'networks' in kwargs:
-            networks = kwargs['networks']
-            networks = [{'uuid': network.id} for network in networks]
-            server_params['networks'] = networks
-
-        if 'ex_security_groups' in kwargs:
-            server_params['security_groups'] = []
-            for security_group in kwargs['ex_security_groups']:
-                name = security_group.name
-                server_params['security_groups'].append({'name': name})
-
-        if 'ex_blockdevicemappings' in kwargs:
-            server_params['block_device_mapping_v2'] = \
-                kwargs['ex_blockdevicemappings']
-
-        if 'name' in kwargs:
-            server_params['name'] = kwargs.get('name')
-        else:
-            server_params['name'] = node.name
-
-        if 'image' in kwargs:
-            server_params['imageRef'] = kwargs.get('image').id
-        else:
-            server_params['imageRef'] = node.extra.get('imageId')
-
-        if 'size' in kwargs:
-            server_params['flavorRef'] = kwargs.get('size').id
-        else:
-            server_params['flavorRef'] = node.extra.get('flavorId')
-
-        return server_params
-
-    def _files_to_personality(self, files):
-        rv = []
-
-        for k, v in list(files.items()):
-            rv.append({'path': k, 'contents': base64.b64encode(b(v))})
-
-        return rv
-
-    def _reboot_node(self, node, reboot_type='SOFT'):
-        resp = self._node_action(node, 'reboot', type=reboot_type)
-        return resp.status == httplib.ACCEPTED
-
-    def ex_set_password(self, node, password):
-        """
-        Changes the administrator password for a specified server.
-
-        :param      node: Node to rebuild.
-        :type       node: :class:`Node`
-
-        :param      password: The administrator password.
-        :type       password: ``str``
-
-        :rtype: ``bool``
-        """
-        resp = self._node_action(node, 'changePassword', adminPass=password)
-        node.extra['password'] = password
-        return resp.status == httplib.ACCEPTED
-
-    def ex_rebuild(self, node, image, **kwargs):
-        """
-        Rebuild a Node.
-
-        :param      node: Node to rebuild.
-        :type       node: :class:`Node`
-
-        :param      image: New image to use.
-        :type       image: :class:`NodeImage`
-
-        :keyword    ex_metadata: Key/Value metadata to associate with a node
-        :type       ex_metadata: ``dict``
-
-        :keyword    ex_files:   File Path => File contents to create on
-                                the no  de
-        :type       ex_files:   ``dict``
-
-        :keyword    ex_keyname:  Name of existing public key to inject into
-                                 instance
-        :type       ex_keyname:  ``str``
-
-        :keyword    ex_userdata: String containing user data
-                                 see
-                                 https://help.ubuntu.com/community/CloudInit
-        :type       ex_userdata: ``str``
-
-        :keyword    ex_security_groups: List of security groups to assign to
-                                        the node
-        :type       ex_security_groups: ``list`` of
-                                       :class:`OpenStackSecurityGroup`
-
-        :keyword    ex_disk_config: Name of the disk configuration.
-                                    Can be either ``AUTO`` or ``MANUAL``.
-        :type       ex_disk_config: ``str``
-
-        :keyword    ex_config_drive: If True enables metadata injection in a
-                                     server through a configuration drive.
-        :type       ex_config_drive: ``bool``
-
-        :rtype: ``bool``
-        """
-        server_params = self._create_args_to_params(node, image=image,
-                                                    **kwargs)
-        resp = self._node_action(node, 'rebuild', **server_params)
-        return resp.status == httplib.ACCEPTED
-
-    def ex_resize(self, node, size):
-        """
-        Change a node size.
-
-        :param      node: Node to resize.
-        :type       node: :class:`Node`
-
-        :type       size: :class:`NodeSize`
-        :param      size: New size to use.
-
-        :rtype: ``bool``
-        """
-        server_params = self._create_args_to_params(node, size=size)
-        resp = self._node_action(node, 'resize', **server_params)
-        return resp.status == httplib.ACCEPTED
-
-    def ex_confirm_resize(self, node):
-        """
-        Confirms a pending resize action.
-
-        :param      node: Node to resize.
-        :type       node: :class:`Node`
-
-        :rtype: ``bool``
-        """
-        resp = self._node_action(node, 'confirmResize')
-        return resp.status == httplib.NO_CONTENT
-
-    def ex_revert_resize(self, node):
-        """
-        Cancels and reverts a pending resize action.
-
-        :param      node: Node to resize.
-        :type       node: :class:`Node`
-
-        :rtype: ``bool``
-        """
-        resp = self._node_action(node, 'revertResize')
-        return resp.status == httplib.ACCEPTED
-
-    def create_image(self, node, name, metadata=None):
-        """
-        Creates a new image.
-
-        :param      node: Node
-        :type       node: :class:`Node`
-
-        :param      name: The name for the new image.
-        :type       name: ``str``
-
-        :param      metadata: Key and value pairs for metadata.
-        :type       metadata: ``dict``
-
-        :rtype: :class:`NodeImage`
-        """
-        optional_params = {}
-        if metadata:
-            optional_params['metadata'] = metadata
-        resp = self._node_action(node, 'createImage', name=name,
-                                 **optional_params)
-        image_id = self._extract_image_id_from_url(resp.headers['location'])
-        return self.get_image(image_id=image_id)
-
-    def ex_set_server_name(self, node, name):
-        """
-        Sets the Node's name.
-
-        :param      node: Node
-        :type       node: :class:`Node`
-
-        :param      name: The name of the server.
-        :type       name: ``str``
-
-        :rtype: :class:`Node`
-        """
-        return self._update_node(node, name=name)
-
-    def ex_get_metadata(self, node):
-        """
-        Get a Node's metadata.
-
-        :param      node: Node
-        :type       node: :class:`Node`
-
-        :return: Key/Value metadata associated with node.
-        :rtype: ``dict``
-        """
-        return self.connection.request(
-            '/servers/%s/metadata' % (node.id,),
-            method='GET',).object['metadata']
-
-    def ex_set_metadata(self, node, metadata):
-        """
-        Sets the Node's metadata.
-
-        :param      node: Node
-        :type       node: :class:`Node`
-
-        :param      metadata: Key/Value metadata to associate with a node
-        :type       metadata: ``dict``
-
-        :rtype: ``dict``
-        """
-        return self.connection.request(
-            '/servers/%s/metadata' % (node.id,), method='PUT',
-            data={'metadata': metadata}
-        ).object['metadata']
-
-    def ex_update_node(self, node, **node_updates):
-        """
-        Update the Node's editable attributes.  The OpenStack API currently
-        supports editing name and IPv4/IPv6 access addresses.
-
-        The driver currently only supports updating the node name.
-
-        :param      node: Node
-        :type       node: :class:`Node`
-
-        :keyword    name:   New name for the server
-        :type       name:   ``str``
-
-        :rtype: :class:`Node`
-        """
-        potential_data = self._create_args_to_params(node, **node_updates)
-        updates = {'name': potential_data['name']}
-        return self._update_node(node, **updates)
-
-    def _to_networks(self, obj):
-        networks = obj['networks']
-        return [self._to_network(network) for network in networks]
-
-    def _to_network(self, obj):
-        return OpenStackNetwork(id=obj['id'],
-                                name=obj['label'],
-                                cidr=obj.get('cidr', None),
-                                driver=self)
-
-    def ex_list_networks(self):
-        """
-        Get a list of Networks that are available.
-
-        :rtype: ``list`` of :class:`OpenStackNetwork`
-        """
-        response = self.connection.request(self._networks_url_prefix).object
-        return self._to_networks(response)
-
-    def ex_create_network(self, name, cidr):
-        """
-        Create a new Network
-
-        :param name: Name of network which should be used
-        :type name: ``str``
-
-        :param cidr: cidr of network which should be used
-        :type cidr: ``str``
-
-        :rtype: :class:`OpenStackNetwork`
-        """
-        data = {'network': {'cidr': cidr, 'label': name}}
-        response = self.connection.request(self._networks_url_prefix,
-                                           method='POST', data=data).object
-        return self._to_network(response['network'])
-
-    def ex_delete_network(self, network):
-        """
-        Get a list of NodeNetorks that are available.
-
-        :param network: Network which should be used
-        :type network: :class:`OpenStackNetwork`
-
-        :rtype: ``bool``
-        """
-        resp = self.connection.request('%s/%s' % (self._networks_url_prefix,
-                                                  network.id),
-                                       method='DELETE')
-        return resp.status == httplib.ACCEPTED
-
-    def ex_get_console_output(self, node, length=None):
-        """
-        Get console output
-
-        :param      node: node
-        :type       node: :class:`Node`
-
-        :param      length: Optional number of lines to fetch from the
-                            console log
-        :type       length: ``int``
-
-        :return: Dictionary with the output
-        :rtype: ``dict``
-        """
-
-        data = {
-            "os-getConsoleOutput": {
-                "length": length
-            }
-        }
-
-        resp = self.connection.request('/servers/%s/action' % node.id,
-                                       method='POST', data=data).object
-        return resp
-
-    def ex_list_snapshots(self):
-        return self._to_snapshots(
-            self.connection.request('/os-snapshots').object)
-
-    def list_volume_snapshots(self, volume):
-        return [snapshot for snapshot in self.ex_list_snapshots()
-                if snapshot.extra['volume_id'] == volume.id]
-
-    def create_volume_snapshot(self, volume, name=None, ex_description=None,
-                               ex_force=True):
-        """
-        Create snapshot from volume
-
-        :param volume: Instance of `StorageVolume`
-        :type  volume: `StorageVolume`
-
-        :param name: Name of snapshot (optional)
-        :type  name: `str`
-
-        :param ex_description: Description of the snapshot (optional)
-        :type  ex_description: `str`
-
-        :param ex_force: Specifies if we create a snapshot that is not in
-                         state `available`. For example `in-use`. Defaults
-                         to True. (optional)
-        :type  ex_force: `bool`
-
-        :rtype: :class:`VolumeSnapshot`
-        """
-        data = {'snapshot': {'display_name': name,
-                             'display_description': ex_description,
-                             'volume_id': volume.id,
-                             'force': ex_force}}
-
-        return self._to_snapshot(self.connection.request('/os-snapshots',
-                                                         method='POST',
-                                                         data=data).object)
-
-    def destroy_volume_snapshot(self, snapshot):
-        resp = self.connection.request('/os-snapshots/%s' % snapshot.id,
-                                       method='DELETE')
-        return resp.status == httplib.NO_CONTENT
-
-    def ex_create_snapshot(self, volume, name, description=None, force=False):
-        """
-        Create a snapshot based off of a volume.
-
-        :param      volume: volume
-        :type       volume: :class:`StorageVolume`
-
-        :keyword    name: New name for the volume snapshot
-        :type       name: ``str``
-
-        :keyword    description: Description of the snapshot (optional)
-        :type       description: ``str``
-
-        :keyword    force: Whether to force creation (optional)
-        :type       force: ``bool``
-
-        :rtype:     :class:`VolumeSnapshot`
-        """
-        warnings.warn('This method has been deprecated in favor of the '
-                      'create_volume_snapshot method')
-        return self.create_volume_snapshot(volume, name,
-                                           ex_description=description,
-                                           ex_force=force)
-
-    def ex_delete_snapshot(self, snapshot):
-        """
-        Delete a VolumeSnapshot
-
-        :param      snapshot: snapshot
-        :type       snapshot: :class:`VolumeSnapshot`
-
-        :rtype:     ``bool``
-        """
-        warnings.warn('This method has been deprecated in favor of the '
-                      'destroy_volume_snapshot method')
-        return self.destroy_volume_snapshot(snapshot)
-
-    def _to_security_group_rules(self, obj):
-        return [self._to_security_group_rule(security_group_rule) for
-                security_group_rule in obj]
-
-    def _to_security_group_rule(self, obj):
-        ip_range = group = tenant_id = None
-        if obj['group'] == {}:
-            ip_range = obj['ip_range'].get('cidr', None)
-        else:
-            group = obj['group'].get('name', None)
-            tenant_id = obj['group'].get('tenant_id', None)
-
-        return OpenStackSecurityGroupRule(
-            id=obj['id'], parent_group_id=obj['parent_group_id'],
-            ip_protocol=obj['ip_protocol'], from_port=obj['from_port'],
-            to_port=obj['to_port'], driver=self, ip_range=ip_range,
-            group=group, tenant_id=tenant_id)
-
-    def _to_security_groups(self, obj):
-        security_groups = obj['security_groups']
-        return [self._to_security_group(security_group) for security_group in
-                security_groups]
-
-    def _to_security_group(self, obj):
-        rules = self._to_security_group_rules(obj.get('rules', []))
-        return OpenStackSecurityGroup(id=obj['id'],
-                                      tenant_id=obj['tenant_id'],
-                                      name=obj['name'],
-                                      description=obj.get('description', ''),
-                                      rules=rules,
-                                      driver=self)
-
-    def ex_list_security_groups(self):
-        """
-        Get a list of Security Groups that are available.
-
-        :rtype: ``list`` of :class:`OpenStackSecurityGroup`
-        """
-        return self._to_security_groups(
-            self.connection.request('/os-security-groups').object)
-
-    def ex_get_node_security_groups(self, node):
-        """
-        Get Security Groups of the specified server.
-
-        :rtype: ``list`` of :class:`OpenStackSecurityGroup`
-        """
-        return self._to_security_groups(
-            self.connection.request('/servers/%s/os-security-groups' %
-                                    (node.id)).object)
-
-    def ex_create_security_group(self, name, description):
-        """
-        Create a new Security Group
-
-        :param name: Name of the new Security Group
-        :type  name: ``str``
-
-        :param description: Description of the new Security Group
-        :type  description: ``str``
-
-        :rtype: :class:`OpenStackSecurityGroup`
-        """
-        return self._to_security_group(self.connection.request(
-            '/os-security-groups', method='POST',
-            data={'security_group': {'name': name, 'description': description}}
-        ).object['security_group'])
-
-    def ex_delete_security_group(self, security_group):
-        """
-        Delete a Security Group.
-
-        :param security_group: Security Group should be deleted
-        :type  security_group: :class:`OpenStackSecurityGroup`
-
-        :rtype: ``bool``
-        """
-        resp = self.connection.request('/os-security-groups/%s' %
-                                       (security_group.id),
-                                       method='DELETE')
-        return resp.status in (httplib.NO_CONTENT, httplib.ACCEPTED)
-
-    def ex_create_security_group_rule(self, security_group, ip_protocol,
-                                      from_port, to_port, cidr=None,
-                                      source_security_group=None):
-        """
-        Create a new Rule in a Security Group
-
-        :param security_group: Security Group in which to add the rule
-        :type  security_group: :class:`OpenStackSecurityGroup`
-
-        :param ip_protocol: Protocol to which this rule applies
-                            Examples: tcp, udp, ...
-        :type  ip_protocol: ``str``
-
-        :param from_port: First port of the port range
-        :type  from_port: ``int``
-
-        :param to_port: Last port of the port range
-        :type  to_port: ``int``
-
-        :param cidr: CIDR notation of the source IP range for this rule
-        :type  cidr: ``str``
-
-        :param source_security_group: Existing Security Group to use as the
-                                      source (instead of CIDR)
-        :type  source_security_group: L{OpenStackSecurityGroup
-
-        :rtype: :class:`OpenStackSecurityGroupRule`
-        """
-        source_security_group_id = None
-        if type(source_security_group) == OpenStackSecurityGroup:
-            source_security_group_id = source_security_group.id
-
-        return self._to_security_group_rule(self.connection.request(
-            '/os-security-group-rules', method='POST',
-            data={'security_group_rule': {
-                'ip_protocol': ip_protocol,
-                'from_port': from_port,
-                'to_port': to_port,
-                'cidr': cidr,
-                'group_id': source_security_group_id,
-                'parent_group_id': security_group.id}}
-        ).object['security_group_rule'])
-
-    def ex_delete_security_group_rule(self, rule):
-        """
-        Delete a Rule from a Security Group.
-
-        :param rule: Rule should be deleted
-        :type  rule: :class:`OpenStackSecurityGroupRule`
-
-        :rtype: ``bool``
-        """
-        resp = self.connection.request('/os-security-group-rules/%s' %
-                                       (rule.id), method='DELETE')
-        return resp.status == httplib.NO_CONTENT
-
-    def _to_key_pairs(self, obj):
-        key_pairs = obj['keypairs']
-        key_pairs = [self._to_key_pair(key_pair['keypair']) for key_pair in
-                     key_pairs]
-        return key_pairs
-
-    def _to_key_pair(self, obj):
-        key_pair = KeyPair(name=obj['name'],
-                           fingerprint=obj['fingerprint'],
-                           public_key=obj['public_key'],
-                           private_key=obj.get('private_key', None),
-                           driver=self)
-        return key_pair
-
-    def list_key_pairs(self):
-        response = self.connection.request('/os-keypairs')
-        key_pairs = self._to_key_pairs(response.object)
-        return key_pairs
-
-    def get_key_pair(self, name):
-        self.connection.set_context({'key_pair_name': name})
-
-        response = self.connection.request('/os-keypairs/%s' % (name))
-        key_pair = self._to_key_pair(response.object['keypair'])
-        return key_pair
-
-    def create_key_pair(self, name):
-        data = {'keypair': {'name': name}}
-        response = self.connection.request('/os-keypairs', method='POST',
-                                           data=data)
-        key_pair = self._to_key_pair(response.object['keypair'])
-        return key_pair
-
-    def import_key_pair_from_string(self, name, key_material):
-        data = {'keypair': {'name': name, 'public_key': key_material}}
-        response = self.connection.request('/os-keypairs', method='POST',
-                                           data=data)
-        key_pair = self._to_key_pair(response.object['keypair'])
-        return key_pair
-
-    def delete_key_pair(self, key_pair):
-        """
-        Delete a KeyPair.
-
-        :param keypair: KeyPair to delete
-        :type  keypair: :class:`OpenStackKeyPair`
-
-        :rtype: ``bool``
-        """
-        response = self.connection.request('/os-keypairs/%s' % (key_pair.name),
-                                           method='DELETE')
-        return response.status == httplib.ACCEPTED
-
-    def ex_list_keypairs(self):
-        """
-        Get a list of KeyPairs that are available.
-
-        :rtype: ``list`` of :class:`OpenStackKeyPair`
-        """
-        warnings.warn('This method has been deprecated in favor of '
-                      'list_key_pairs method')
-
-        return self.list_key_pairs()
-
-    def ex_create_keypair(self, name):
-        """
-        Create a new KeyPair
-
-        :param name: Name of the new KeyPair
-        :type  name: ``str``
-
-        :rtype: :class:`OpenStackKeyPair`
-        """
-        warnings.warn('This method has been deprecated in favor of '
-                      'create_key_pair method')
-
-        return self.create_key_pair(name=name)
-
-    def ex_import_keypair(self, name, keyfile):
-        """
-        Import a KeyPair from a file
-
-        :param name: Name of the new KeyPair
-        :type  name: ``str``
-
-        :param keyfile: Path to the public key file (in OpenSSH format)
-        :type  keyfile: ``str``
-
-        :rtype: :class:`OpenStackKeyPair`
-        """
-        warnings.warn('This method has been deprecated in favor of '
-                      'import_key_pair_from_file method')
-
-        return self.import_key_pair_from_file(name=name, key_file_path=keyfile)
-
-    def ex_import_keypair_from_string(self, name, key_material):
-        """
-        Import a KeyPair from a string
-
-        :param name: Name of the new KeyPair
-        :type  name: ``str``
-
-        :param key_material: Public key (in OpenSSH format)
-        :type  key_material: ``str``
-
-        :rtype: :class:`OpenStackKeyPair`
-        """
-        warnings.warn('This method has been deprecated in favor of '
-                      'import_key_pair_from_string method')
-
-        return self.import_key_pair_from_string(name=name,
-                                                key_material=key_material)
-
-    def ex_delete_keypair(self, keypair):
-        """
-        Delete a KeyPair.
-
-        :param keypair: KeyPair to delete
-        :type  keypair: :class:`OpenStackKeyPair`
-
-        :rtype: ``bool``
-        """
-        warnings.warn('This method has been deprecated in favor of '
-                      'delete_key_pair method')
-
-        return self.delete_key_pair(key_pair=keypair)
-
-    def ex_get_size(self, size_id):
-        """
-        Get a NodeSize
-
-        :param      size_id: ID of the size which should be used
-        :type       size_id: ``str``
-
-        :rtype: :class:`NodeSize`
-        """
-        return self._to_size(self.connection.request(
-            '/flavors/%s' % (size_id,)) .object['flavor'])
-
-    def get_image(self, image_id):
-        """
-        Get a NodeImage
-
-        @inherits: :class:`NodeDriver.get_image`
-
-        :param      image_id: ID of the image which should be used
-        :type       image_id: ``str``
-
-        :rtype: :class:`NodeImage`
-        """
-        return self._to_image(self.connection.request(
-            '/images/%s' % (image_id,)).object['image'])
-
-    def delete_image(self, image):
-        """
-        Delete a NodeImage
-
-        @inherits: :class:`NodeDriver.delete_image`
-
-        :param      image: image witch should be used
-        :type       image: :class:`NodeImage`
-
-        :rtype: ``bool``
-        """
-        resp = self.connection.request('/images/%s' % (image.id,),
-                                       method='DELETE')
-        return resp.status == httplib.NO_CONTENT
-
-    def _node_action(self, node, action, **params):
-        params = params or None
-        return self.connection.request('/servers/%s/action' % (node.id,),
-                                       method='POST', data={action: params})
-
-    def _update_node(self, node, **node_updates):
-        """
-        Updates the editable attributes of a server, which currently include
-        its name and IPv4/IPv6 access addresses.
-        """
-        return self._to_node(
-            self.connection.request(
-                '/servers/%s' % (node.id,), method='PUT',
-                data={'server': node_updates}
-            ).object['server']
-        )
-
-    def _to_node_from_obj(self, obj):
-        return self._to_node(obj['server'])
-
-    def _to_node(self, api_node):
-        public_networks_labels = ['public', 'internet']
-
-        public_ips, private_ips = [], []
-
-        for label, values in api_node['addresses'].items():
-            for value in values:
-                ip = value['addr']
-                is_public_ip = False
-
-                try:
-                    is_public_ip = is_public_subnet(ip)
-                except:
-                    # IPv6
-
-                    # Openstack Icehouse sets 'OS-EXT-IPS:type' to 'floating'
-                    # for public and 'fixed' for private
-                    explicit_ip_type = value.get('OS-EXT-IPS:type', None)
-
-                    if label in public_networks_labels:
-                        is_public_ip = True
-                    elif explicit_ip_type == 'floating':
-                        is_public_ip = True
-                    elif explicit_ip_type == 'fixed':
-                        is_public_ip = False
-
-                if is_public_ip:
-                    public_ips.append(ip)
-                else:
-                    private_ips.append(ip)
-
-        # Sometimes 'image' attribute is not present if the node is in an error
-        # state
-        image = api_node.get('image', None)
-        image_id = image.get('id', None) if image else None
-        config_drive = api_node.get("config_drive", False)
-        volumes_attached = api_node.get('os-extended-volumes:volumes_attached')
-        created = parse_date(api_node["created"])
-
-        return Node(
-            id=api_node['id'],
-            name=api_node['name'],
-            state=self.NODE_STATE_MAP.get(api_node['status'],
-                                          NodeState.UNKNOWN),
-            public_ips=public_ips,
-            private_ips=private_ips,
-            created_at=created,
-            driver=self,
-            extra=dict(
-                addresses=api_node['addresses'],
-                hostId=api_node['hostId'],
-                access_ip=api_node.get('accessIPv4'),
-                access_ipv6=api_node.get('accessIPv6', None),
-                # Docs says "tenantId", but actual is "tenant_id". *sigh*
-                # Best handle both.
-                tenantId=api_node.get('tenant_id') or api_node['tenantId'],
-                userId=api_node.get('user_id', None),
-                imageId=image_id,
-                flavorId=api_node['flavor']['id'],
-                uri=next(link['href'] for link in api_node['links'] if
-                         link['rel'] == 'self'),
-                service_name=self.connection.get_service_name(),
-                metadata=api_node['metadata'],
-                password=api_node.get('adminPass', None),
-                created=api_node['created'],
-                updated=api_node['updated'],
-                key_name=api_node.get('key_name', None),
-                disk_config=api_node.get('OS-DCF:diskConfig', None),
-                config_drive=config_drive,
-                availability_zone=api_node.get('OS-EXT-AZ:availability_zone'),
-                volumes_attached=volumes_attached,
-                task_state=api_node.get("OS-EXT-STS:task_state", None),
-                vm_state=api_node.get("OS-EXT-STS:vm_state", None),
-                power_state=api_node.get("OS-EXT-STS:power_state", None),
-                progress=api_node.get("progress", None),
-                fault=api_node.get('fault')
-            ),
-        )
-
-    def _to_volume(self, api_node):
-        if 'volume' in api_node:
-            api_node = api_node['volume']
-
-        state = self.VOLUME_STATE_MAP.get(api_node['status'],
-                                          StorageVolumeState.UNKNOWN)
-
-        return StorageVolume(
-            id=api_node['id'],
-            name=api_node['displayName'],
-            size=api_node['size'],
-            state=state,
-            driver=self,
-            extra={
-                'description': api_node['displayDescription'],
-                'attachments': [att for att in api_node['attachments'] if att],
-                # TODO: remove in 1.18.0
-                'state': api_node.get('status', None),
-                'snapshot_id': api_node.get('snapshotId', None),
-                'location': api_node.get('availabilityZone', None),
-                'volume_type': api_node.get('volumeType', None),
-                'metadata': api_node.get('metadata', None),
-                'created_at': api_node.get('createdAt', None)
-            }
-        )
-
-    def _to_snapshot(self, data):
-        if 'snapshot' in data:
-            data = data['snapshot']
-
-        volume_id = data.get('volume_id', data.get('volumeId', None))
-        display_name = data.get('display_name', data.get('displayName', None))
-        created_at = data.get('created_at', data.get('createdAt', None))
-        description = data.get('display_description',
-                               data.get('displayDescription', None))
-        status = data.get('status', None)
-
-        extra = {'volume_id': volume_id,
-                 'name': display_name,
-                 'created': created_at,
-                 'description': description,
-                 'status': status}
-
-        state = self.SNAPSHOT_STATE_MAP.get(
-            status,
-            VolumeSnapshotState.UNKNOWN
-        )
-
-        try:
-            created_dt = parse_date(created_at)
-        except ValueError:
-            created_dt = None
-
-        snapshot = VolumeSnapshot(id=data['id'], driver=self,
-                                  size=data['size'], extra=extra,
-                                  created=created_dt, state=state)
-        return snapshot
-
-    def _to_size(self, api_flavor, price=None, bandwidth=None):
-        # if provider-specific subclasses can get better values for
-        # price/bandwidth, then can pass them in when they super().
-        if not price:
-            price = self._get_size_price(str(api_flavor['id']))
-
-        extra = api_flavor.get('OS-FLV-WITH-EXT-SPECS:extra_specs', {})
-        return OpenStackNodeSize(
-            id=api_flavor['id'],
-            name=api_flavor['name'],
-            ram=api_flavor['ram'],
-            disk=api_flavor['disk'],
-            vcpus=api_flavor['vcpus'],
-            ephemeral_disk=api_flavor.get('OS-FLV-EXT-DATA:ephemeral', None),
-            swap=api_flavor['swap'],
-            extra=extra,
-            bandwidth=bandwidth,
-            price=price,
-            driver=self,
-        )
-
-    def _get_size_price(self, size_id):
-        try:
-            return get_size_price(
-                driver_type='compute',
-                driver_name=self.api_name,
-                size_id=size_id,
-            )
-        except KeyError:
-            return(0.0)
-
-    def _extract_image_id_from_url(self, location_header):
-        path = urlparse.urlparse(location_header).path
-        image_id = path.split('/')[-1]
-        return image_id
-
-    def ex_rescue(self, node, password=None):
-        # Requires Rescue Mode extension
-        """
-        Rescue a node
-
-        :param      node: node
-        :type       node: :class:`Node`
-
-        :param      password: password
-        :type       password: ``str``
-
-        :rtype: :class:`Node`
-        """
-        if password:
-            resp = self._node_action(node, 'rescue', adminPass=password)
-        else:
-            resp = self._node_action(node, 'rescue')
-            password = json.loads(resp.body)['adminPass']
-        node.extra['password'] = password
-        return node
-
-    def ex_unrescue(self, node):
-        """
-        Unrescue a node
-
-        :param      node: node
-        :type       node: :class:`Node`
-
-        :rtype: ``bool``
-        """
-        resp = self._node_action(node, 'unrescue')
-        return resp.status == httplib.ACCEPTED
-
-    def _to_floating_ip_pools(self, obj):
-        pool_elements = obj['floating_ip_pools']
-        return [self._to_floating_ip_pool(pool) for pool in pool_elements]
-
-    def _to_floating_ip_pool(self, obj):
-        return OpenStack_1_1_FloatingIpPool(obj['name'], self.connection)
-
-    def ex_list_floating_ip_pools(self):
-        """
-        List available floating IP pools
-
-        :rtype: ``list`` of :class:`OpenStack_1_1_FloatingIpPool`
-        """
-        return self._to_floating_ip_pools(
-            self.connection.request('/os-floating-ip-pools').object)
-
-    def _to_floating_ips(self, obj):
-        ip_elements = obj['floating_ips']
-        return [self._to_floating_ip(ip) for ip in ip_elements]
-
-    def _to_floating_ip(self, obj):
-        return OpenStack_1_1_FloatingIpAddress(id=obj['id'],
-                                               ip_address=obj['ip'],
-                                               pool=None,
-                                               node_id=obj['instance_id'],
-                                               driver=self)
-
-    def ex_list_floating_ips(self):
-        """
-        List floating IPs
-
-        :rtype: ``list`` of :class:`OpenStack_1_1_FloatingIpAddress`
-        """
-        return self._to_floating_ips(
-            self.connection.request('/os-floating-ips').object)
-
-    def ex_get_floating_ip(self, ip):
-        """
-        Get specified floating IP
-
-        :param      ip: floating IP to get
-        :type       ip: ``str``
-
-        :rtype: :class:`OpenStack_1_1_FloatingIpAddress`
-        """
-        floating_ips = self.ex_list_floating_ips()
-        ip_obj, = [x for x in floating_ips if x.ip_address == ip]
-        return ip_obj
-
-    def ex_create_floating_ip(self, ip_pool=None):
-        """
-        Create new floating IP. The ip_pool attribute is optional only if your
-        infrastructure has only one IP pool available.
-
-        :param      ip_pool: name of the floating IP pool
-        :type       ip_pool: ``str``
-
-        :rtype: :class:`OpenStack_1_1_FloatingIpAddress`
-        """
-        data = {'pool': ip_pool} if ip_pool is not None else {}
-        resp = self.connection.request('/os-floating-ips',
-                                       method='POST',
-                                       data=data)
-
-        data = resp.object['floating_ip']
-        id = data['id']
-        ip_address = data['ip']
-        return OpenStack_1_1_FloatingIpAddress(id=id,
-                                               ip_address=ip_address,
-                                               pool=None,
-                                               node_id=None,
-                                               driver=self)
-
-    def ex_delete_floating_ip(self, ip):
-        """
-        Delete specified floating IP
-
-        :param      ip: floating IP to remove
-        :type       ip: :class:`OpenStack_1_1_FloatingIpAddress`
-
-        :rtype: ``bool``
-        """
-        resp = self.connection.request('/os-floating-ips/%s' % ip.id,
-                                       method='DELETE')
-        return resp.status in (httplib.NO_CONTENT, httplib.ACCEPTED)
-
-    def ex_attach_floating_ip_to_node(self, node, ip):
-        """
-        Attach the floating IP to the node
-
-        :param      node: node
-        :type       node: :class:`Node`
-
-        :param      ip: floating IP to attach
-        :type       ip: ``str`` or :class:`OpenStack_1_1_FloatingIpAddress`
-
-        :rtype: ``bool``
-        """
-        address = ip.ip_address if hasattr(ip, 'ip_address') else ip
-        data = {
-            'addFloatingIp': {'address': address}
-        }
-        resp = self.connection.request('/servers/%s/action' % node.id,
-                                       method='POST', data=data)
-        return resp.status == httplib.ACCEPTED
-
-    def ex_detach_floating_ip_from_node(self, node, ip):
-        """
-        Detach the floating IP from the node
-
-        :param      node: node
-        :type       node: :class:`Node`
-
-        :param      ip: floating IP to remove
-        :type       ip: ``str`` or :class:`OpenStack_1_1_FloatingIpAddress`
-
-        :rtype: ``bool``
-        """
-        address = ip.ip_address if hasattr(ip, 'ip_address') else ip
-        data = {
-            'removeFloatingIp': {'address': address}
-        }
-        resp = self.connection.request('/servers/%s/action' % node.id,
-                                       method='POST', data=data)
-        return resp.status == httplib.ACCEPTED
-
-    def ex_get_metadata_for_node(self, node):
-        """
-        Return the metadata associated with the node.
-
-        :param      node: Node instance
-        :type       node: :class:`Node`
-
-        :return: A dictionary or other mapping of strings to strings,
-                 associating tag names with tag values.
-        :type tags: ``dict``
-        """
-        return node.extra['metadata']
-
-    def ex_pause_node(self, node):
-        uri = '/servers/%s/action' % (node.id)
-        data = {'pause': None}
-        resp = self.connection.request(uri, method='POST', data=data)
-        return resp.status == httplib.ACCEPTED
-
-    def ex_unpause_node(self, node):
-        uri = '/servers/%s/action' % (node.id)
-        data = {'unpause': None}
-        resp = self.connection.request(uri, method='POST', data=data)
-        return resp.status == httplib.ACCEPTED
-
-    def ex_suspend_node(self, node):
-        uri = '/servers/%s/action' % (node.id)
-        data = {'suspend': None}
-        resp = self.connection.request(uri, method='POST', data=data)
-        return resp.status == httplib.ACCEPTED
-
-    def ex_resume_node(self, node):
-        uri = '/servers/%s/action' % (node.id)
-        data = {'resume': None}
-        resp = self.connection.request(uri, method='POST', data=data)
-        return resp.status == httplib.ACCEPTED
-
-
-class OpenStack_1_1_FloatingIpPool(object):
-    """
-    Floating IP Pool info.
-    """
-
-    def __init__(self, name, connection):
-        self.name = name
-        self.connection = connection
-
-    def list_floating_ips(self):
-        """
-        List floating IPs in the pool
-
-        :rtype: ``list`` of :class:`OpenStack_1_1_FloatingIpAddress`
-        """
-        return self._to_floating_ips(
-            self.connection.request('/os-floating-ips').object)
-
-    def _to_floating_ips(self, obj):
-        ip_elements = obj['floating_ips']
-        return [self._to_floating_ip(ip) for ip in ip_elements]
-
-    def _to_floating_ip(self, obj):
-        return OpenStack_1_1_FloatingIpAddress(id=obj['id'],
-                                               ip_address=obj['ip'],
-                                               pool=self,
-                                               node_id=obj['instance_id'],
-                                               driver=self.connection.driver)
-
-    def get_floating_ip(self, ip):
-        """
-        Get specified floating IP from the pool
-
-        :param      ip: floating IP to get
-        :type       ip: ``str``
-
-        :rtype: :class:`OpenStack_1_1_FloatingIpAddress`
-        """
-        ip_obj, = [x for x in self.list_floating_ips() if x.ip_address == ip]
-        return ip_obj
-
-    def create_floating_ip(self):
-        """
-        Create new floating IP in the pool
-
-        :rtype: :class:`OpenStack_1_1_FloatingIpAddress`
-        """
-        resp = self.connection.request('/os-floating-ips',
-                                       method='POST',
-                                       data={'pool': self.name})
-        data = resp.object['floating_ip']
-        id = data['id']
-        ip_address = data['ip']
-        return OpenStack_1_1_FloatingIpAddress(id=id,
-                                               ip_address=ip_address,
-                                               pool=self,
-                                               node_id=None,
-                                               driver=self.connection.driver)
-
-    def delete_floating_ip(self, ip):
-        """
-        Delete specified floating IP from the pool
-
-        :param      ip: floating IP to remove
-        :type       ip::class:`OpenStack_1_1_FloatingIpAddress`
-
-        :rtype: ``bool``
-        """
-        resp = self.connection.request('/os-floating-ips/%s' % ip.id,
-                                       method='DELETE')
-        return resp.status in (httplib.NO_CONTENT, httplib.ACCEPTED)
-
-    def __repr__(self):
-        return ('<OpenStack_1_1_FloatingIpPool: name=%s>' % self.name)
-
-
-cl

<TRUNCATED>