http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/elasticstack.py
----------------------------------------------------------------------
diff --git a/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/elasticstack.py 
b/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/elasticstack.py
deleted file mode 100644
index 18b581b..0000000
--- a/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/elasticstack.py
+++ /dev/null
@@ -1,495 +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.
-
-"""
-Base driver for the providers based on the ElasticStack platform -
-http://www.elasticstack.com.
-"""
-
-import re
-import time
-import base64
-
-from libcloud.utils.py3 import httplib
-from libcloud.utils.py3 import b
-
-try:
-    import simplejson as json
-except ImportError:
-    import json
-
-from libcloud.common.base import ConnectionUserAndKey, JsonResponse
-from libcloud.common.types import InvalidCredsError
-from libcloud.compute.types import NodeState
-from libcloud.compute.base import NodeDriver, NodeSize, Node
-from libcloud.compute.base import NodeImage
-from libcloud.compute.deployment import ScriptDeployment, SSHKeyDeployment
-from libcloud.compute.deployment import MultiStepDeployment
-
-
-NODE_STATE_MAP = {
-    'active': NodeState.RUNNING,
-    'dead': NodeState.TERMINATED,
-    'dumped': NodeState.TERMINATED,
-}
-
-# Default timeout (in seconds) for the drive imaging process
-IMAGING_TIMEOUT = 10 * 60
-
-# ElasticStack doesn't specify special instance types, so I just specified
-# some plans based on the other provider offerings.
-#
-# Basically for CPU any value between 500Mhz and 20000Mhz should work,
-# 256MB to 8192MB for ram and 1GB to 2TB for disk.
-INSTANCE_TYPES = {
-    'small': {
-        'id': 'small',
-        'name': 'Small instance',
-        'cpu': 2000,
-        'memory': 1700,
-        'disk': 160,
-        'bandwidth': None,
-    },
-    'medium': {
-        'id': 'medium',
-        'name': 'Medium instance',
-        'cpu': 3000,
-        'memory': 4096,
-        'disk': 500,
-        'bandwidth': None,
-    },
-    'large': {
-        'id': 'large',
-        'name': 'Large instance',
-        'cpu': 4000,
-        'memory': 7680,
-        'disk': 850,
-        'bandwidth': None,
-    },
-    'extra-large': {
-        'id': 'extra-large',
-        'name': 'Extra Large instance',
-        'cpu': 8000,
-        'memory': 8192,
-        'disk': 1690,
-        'bandwidth': None,
-    },
-    'high-cpu-medium': {
-        'id': 'high-cpu-medium',
-        'name': 'High-CPU Medium instance',
-        'cpu': 5000,
-        'memory': 1700,
-        'disk': 350,
-        'bandwidth': None,
-    },
-    'high-cpu-extra-large': {
-        'id': 'high-cpu-extra-large',
-        'name': 'High-CPU Extra Large instance',
-        'cpu': 20000,
-        'memory': 7168,
-        'disk': 1690,
-        'bandwidth': None,
-    },
-}
-
-
-class ElasticStackException(Exception):
-    def __str__(self):
-        return self.args[0]
-
-    def __repr__(self):
-        return "<ElasticStackException '%s'>" % (self.args[0])
-
-
-class ElasticStackResponse(JsonResponse):
-    def success(self):
-        if self.status == 401:
-            raise InvalidCredsError()
-
-        return self.status >= 200 and self.status <= 299
-
-    def parse_error(self):
-        error_header = self.headers.get('x-elastic-error', '')
-        return 'X-Elastic-Error: %s (%s)' % (error_header, self.body.strip())
-
-
-class ElasticStackNodeSize(NodeSize):
-    def __init__(self, id, name, cpu, ram, disk, bandwidth, price, driver):
-        self.id = id
-        self.name = name
-        self.cpu = cpu
-        self.ram = ram
-        self.disk = disk
-        self.bandwidth = bandwidth
-        self.price = price
-        self.driver = driver
-
-    def __repr__(self):
-        return (('<NodeSize: id=%s, name=%s, cpu=%s, ram=%s '
-                 'disk=%s bandwidth=%s price=%s driver=%s ...>')
-                % (self.id, self.name, self.cpu, self.ram,
-                   self.disk, self.bandwidth, self.price, self.driver.name))
-
-
-class ElasticStackBaseConnection(ConnectionUserAndKey):
-    """
-    Base connection class for the ElasticStack driver
-    """
-
-    host = None
-    responseCls = ElasticStackResponse
-
-    def add_default_headers(self, headers):
-        headers['Accept'] = 'application/json'
-        headers['Content-Type'] = 'application/json'
-        headers['Authorization'] = \
-            ('Basic %s' % (base64.b64encode(b('%s:%s' % (self.user_id,
-                                                         self.key))))
-                .decode('utf-8'))
-        return headers
-
-
-class ElasticStackBaseNodeDriver(NodeDriver):
-    website = 'http://www.elasticstack.com'
-    connectionCls = ElasticStackBaseConnection
-    features = {"create_node": ["generates_password"]}
-
-    def reboot_node(self, node):
-        # Reboots the node
-        response = self.connection.request(
-            action='/servers/%s/reset' % (node.id),
-            method='POST'
-        )
-        return response.status == 204
-
-    def destroy_node(self, node):
-        # Kills the server immediately
-        response = self.connection.request(
-            action='/servers/%s/destroy' % (node.id),
-            method='POST'
-        )
-        return response.status == 204
-
-    def list_images(self, location=None):
-        # Returns a list of available pre-installed system drive images
-        images = []
-        for key, value in self._standard_drives.items():
-            image = NodeImage(
-                id=value['uuid'],
-                name=value['description'],
-                driver=self.connection.driver,
-                extra={
-                    'size_gunzipped': value['size_gunzipped']
-                }
-            )
-            images.append(image)
-
-        return images
-
-    def list_sizes(self, location=None):
-        sizes = []
-        for key, value in INSTANCE_TYPES.items():
-            size = ElasticStackNodeSize(
-                id=value['id'],
-                name=value['name'], cpu=value['cpu'], ram=value['memory'],
-                disk=value['disk'], bandwidth=value['bandwidth'],
-                price=self._get_size_price(size_id=value['id']),
-                driver=self.connection.driver
-            )
-            sizes.append(size)
-
-        return sizes
-
-    def list_nodes(self):
-        # Returns a list of active (running) nodes
-        response = self.connection.request(action='/servers/info').object
-
-        nodes = []
-        for data in response:
-            node = self._to_node(data)
-            nodes.append(node)
-
-        return nodes
-
-    def create_node(self, **kwargs):
-        """Creates an ElasticStack instance
-
-        @inherits: :class:`NodeDriver.create_node`
-
-        :keyword    name: String with a name for this new node (required)
-        :type       name: ``str``
-
-        :keyword    smp: Number of virtual processors or None to calculate
-                         based on the cpu speed
-        :type       smp: ``int``
-
-        :keyword    nic_model: e1000, rtl8139 or virtio
-                               (if not specified, e1000 is used)
-        :type       nic_model: ``str``
-
-        :keyword    vnc_password: If set, the same password is also used for
-                                  SSH access with user toor,
-                                  otherwise VNC access is disabled and
-                                  no SSH login is possible.
-        :type       vnc_password: ``str``
-        """
-        size = kwargs['size']
-        image = kwargs['image']
-        smp = kwargs.get('smp', 'auto')
-        nic_model = kwargs.get('nic_model', 'e1000')
-        vnc_password = ssh_password = kwargs.get('vnc_password', None)
-
-        if nic_model not in ('e1000', 'rtl8139', 'virtio'):
-            raise ElasticStackException('Invalid NIC model specified')
-
-        # check that drive size is not smaller than pre installed image size
-
-        # First we create a drive with the specified size
-        drive_data = {}
-        drive_data.update({'name': kwargs['name'],
-                           'size': '%sG' % (kwargs['size'].disk)})
-
-        response = self.connection.request(action='/drives/create',
-                                           data=json.dumps(drive_data),
-                                           method='POST').object
-
-        if not response:
-            raise ElasticStackException('Drive creation failed')
-
-        drive_uuid = response['drive']
-
-        # Then we image the selected pre-installed system drive onto it
-        response = self.connection.request(
-            action='/drives/%s/image/%s/gunzip' % (drive_uuid, image.id),
-            method='POST'
-        )
-
-        if response.status not in (200, 204):
-            raise ElasticStackException('Drive imaging failed')
-
-        # We wait until the drive is imaged and then boot up the node
-        # (in most cases, the imaging process shouldn't take longer
-        # than a few minutes)
-        response = self.connection.request(
-            action='/drives/%s/info' % (drive_uuid)
-        ).object
-
-        imaging_start = time.time()
-        while 'imaging' in response:
-            response = self.connection.request(
-                action='/drives/%s/info' % (drive_uuid)
-            ).object
-
-            elapsed_time = time.time() - imaging_start
-            if ('imaging' in response and elapsed_time >= IMAGING_TIMEOUT):
-                raise ElasticStackException('Drive imaging timed out')
-
-            time.sleep(1)
-
-        node_data = {}
-        node_data.update({'name': kwargs['name'],
-                          'cpu': size.cpu,
-                          'mem': size.ram,
-                          'ide:0:0': drive_uuid,
-                          'boot': 'ide:0:0',
-                          'smp': smp})
-        node_data.update({'nic:0:model': nic_model, 'nic:0:dhcp': 'auto'})
-
-        if vnc_password:
-            node_data.update({'vnc': 'auto', 'vnc:password': vnc_password})
-
-        response = self.connection.request(
-            action='/servers/create', data=json.dumps(node_data),
-            method='POST'
-        ).object
-
-        if isinstance(response, list):
-            nodes = [self._to_node(node, ssh_password) for node in response]
-        else:
-            nodes = self._to_node(response, ssh_password)
-
-        return nodes
-
-    # Extension methods
-    def ex_set_node_configuration(self, node, **kwargs):
-        """
-        Changes the configuration of the running server
-
-        :param      node: Node which should be used
-        :type       node: :class:`Node`
-
-        :param      kwargs: keyword arguments
-        :type       kwargs: ``dict``
-
-        :rtype: ``bool``
-        """
-        valid_keys = ('^name$', '^parent$', '^cpu$', '^smp$', '^mem$',
-                      '^boot$', '^nic:0:model$', '^nic:0:dhcp',
-                      '^nic:1:model$', '^nic:1:vlan$', '^nic:1:mac$',
-                      '^vnc:ip$', '^vnc:password$', '^vnc:tls',
-                      '^ide:[0-1]:[0-1](:media)?$',
-                      '^scsi:0:[0-7](:media)?$', '^block:[0-7](:media)?$')
-
-        invalid_keys = []
-        keys = list(kwargs.keys())
-        for key in keys:
-            matches = False
-            for regex in valid_keys:
-                if re.match(regex, key):
-                    matches = True
-                    break
-            if not matches:
-                invalid_keys.append(key)
-
-        if invalid_keys:
-            raise ElasticStackException(
-                'Invalid configuration key specified: %s'
-                % (',' .join(invalid_keys))
-            )
-
-        response = self.connection.request(
-            action='/servers/%s/set' % (node.id), data=json.dumps(kwargs),
-            method='POST'
-        )
-
-        return (response.status == httplib.OK and response.body != '')
-
-    def deploy_node(self, **kwargs):
-        """
-        Create a new node, and start deployment.
-
-        @inherits: :class:`NodeDriver.deploy_node`
-
-        :keyword    enable_root: If true, root password will be set to
-                                 vnc_password (this will enable SSH access)
-                                 and default 'toor' account will be deleted.
-        :type       enable_root: ``bool``
-        """
-        image = kwargs['image']
-        vnc_password = kwargs.get('vnc_password', None)
-        enable_root = kwargs.get('enable_root', False)
-
-        if not vnc_password:
-            raise ValueError('You need to provide vnc_password argument '
-                             'if you want to use deployment')
-
-        if (image in self._standard_drives and
-                not self._standard_drives[image]['supports_deployment']):
-            raise ValueError('Image %s does not support deployment'
-                             % (image.id))
-
-        if enable_root:
-            script = ("unset HISTFILE;"
-                      "echo root:%s | chpasswd;"
-                      "sed -i '/^toor.*$/d' /etc/passwd /etc/shadow;"
-                      "history -c") % vnc_password
-            root_enable_script = ScriptDeployment(script=script,
-                                                  delete=True)
-            deploy = kwargs.get('deploy', None)
-            if deploy:
-                if (isinstance(deploy, ScriptDeployment) or
-                        isinstance(deploy, SSHKeyDeployment)):
-                    deployment = MultiStepDeployment([deploy,
-                                                      root_enable_script])
-                elif isinstance(deploy, MultiStepDeployment):
-                    deployment = deploy
-                    deployment.add(root_enable_script)
-            else:
-                deployment = root_enable_script
-
-            kwargs['deploy'] = deployment
-
-        if not kwargs.get('ssh_username', None):
-            kwargs['ssh_username'] = 'toor'
-
-        return super(ElasticStackBaseNodeDriver, self).deploy_node(**kwargs)
-
-    def ex_shutdown_node(self, node):
-        """
-        Sends the ACPI power-down event
-
-        :param      node: Node which should be used
-        :type       node: :class:`Node`
-
-        :rtype: ``bool``
-        """
-        response = self.connection.request(
-            action='/servers/%s/shutdown' % (node.id),
-            method='POST'
-        )
-        return response.status == 204
-
-    def ex_destroy_drive(self, drive_uuid):
-        """
-        Deletes a drive
-
-        :param      drive_uuid: Drive uuid which should be used
-        :type       drive_uuid: ``str``
-
-        :rtype: ``bool``
-        """
-        response = self.connection.request(
-            action='/drives/%s/destroy' % (drive_uuid),
-            method='POST'
-        )
-        return response.status == 204
-
-    # Helper methods
-    def _to_node(self, data, ssh_password=None):
-        try:
-            state = NODE_STATE_MAP[data['status']]
-        except KeyError:
-            state = NodeState.UNKNOWN
-
-        if 'nic:0:dhcp:ip' in data:
-            if isinstance(data['nic:0:dhcp:ip'], list):
-                public_ip = data['nic:0:dhcp:ip']
-            else:
-                public_ip = [data['nic:0:dhcp:ip']]
-        else:
-            public_ip = []
-
-        extra = {'cpu': data['cpu'],
-                 'mem': data['mem']}
-
-        if 'started' in data:
-            extra['started'] = data['started']
-
-        if 'smp' in data:
-            extra['smp'] = data['smp']
-
-        if 'vnc:ip' in data:
-            extra['vnc:ip'] = data['vnc:ip']
-
-        if 'vnc:password' in data:
-            extra['vnc:password'] = data['vnc:password']
-
-        boot_device = data['boot']
-
-        if isinstance(boot_device, list):
-            for device in boot_device:
-                extra[device] = data[device]
-        else:
-            extra[boot_device] = data[boot_device]
-
-        if ssh_password:
-            extra.update({'password': ssh_password})
-
-        node = Node(id=data['server'], name=data['name'], state=state,
-                    public_ips=public_ip, private_ips=None,
-                    driver=self.connection.driver,
-                    extra=extra)
-
-        return node

http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/exoscale.py
----------------------------------------------------------------------
diff --git a/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/exoscale.py 
b/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/exoscale.py
deleted file mode 100644
index 9f883e0..0000000
--- a/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/exoscale.py
+++ /dev/null
@@ -1,31 +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.
-
-from libcloud.compute.providers import Provider
-from libcloud.compute.drivers.cloudstack import CloudStackNodeDriver
-
-__all__ = [
-    'ExoscaleNodeDriver'
-]
-
-
-class ExoscaleNodeDriver(CloudStackNodeDriver):
-    type = Provider.EXOSCALE
-    name = 'Exoscale'
-    website = 'https://www.exoscale.ch/'
-
-    # API endpoint info
-    host = 'api.exoscale.ch'
-    path = '/compute'

http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/gandi.py
----------------------------------------------------------------------
diff --git a/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/gandi.py 
b/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/gandi.py
deleted file mode 100644
index 844850a..0000000
--- a/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/gandi.py
+++ /dev/null
@@ -1,825 +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.
-"""
-Gandi driver for compute
-"""
-import sys
-from datetime import datetime
-
-from libcloud.common.gandi import BaseGandiDriver, GandiException,\
-    NetworkInterface, IPAddress, Disk
-from libcloud.compute.base import KeyPair
-from libcloud.compute.base import StorageVolume
-from libcloud.compute.types import NodeState, Provider
-from libcloud.compute.base import Node, NodeDriver
-from libcloud.compute.base import NodeSize, NodeImage, NodeLocation
-
-
-NODE_STATE_MAP = {
-    'running': NodeState.RUNNING,
-    'halted': NodeState.TERMINATED,
-    'paused': NodeState.TERMINATED,
-    'locked': NodeState.TERMINATED,
-    'being_created': NodeState.PENDING,
-    'invalid': NodeState.UNKNOWN,
-    'legally_locked': NodeState.PENDING,
-    'deleted': NodeState.TERMINATED
-}
-
-NODE_PRICE_HOURLY_USD = 0.02
-
-INSTANCE_TYPES = {
-    'small': {
-        'id': 'small',
-        'name': 'Small instance',
-        'cpu': 1,
-        'memory': 256,
-        'disk': 3,
-        'bandwidth': 10240,
-    },
-    'medium': {
-        'id': 'medium',
-        'name': 'Medium instance',
-        'cpu': 1,
-        'memory': 1024,
-        'disk': 20,
-        'bandwidth': 10240,
-    },
-    'large': {
-        'id': 'large',
-        'name': 'Large instance',
-        'cpu': 2,
-        'memory': 2048,
-        'disk': 50,
-        'bandwidth': 10240,
-    },
-    'x-large': {
-        'id': 'x-large',
-        'name': 'Extra Large instance',
-        'cpu': 4,
-        'memory': 4096,
-        'disk': 100,
-        'bandwidth': 10240,
-    },
-}
-
-
-class GandiNodeDriver(BaseGandiDriver, NodeDriver):
-    """
-    Gandi node driver
-
-    """
-    api_name = 'gandi'
-    friendly_name = 'Gandi.net'
-    website = 'http://www.gandi.net/'
-    country = 'FR'
-    type = Provider.GANDI
-    # TODO : which features to enable ?
-    features = {}
-
-    def __init__(self, *args, **kwargs):
-        """
-        @inherits: :class:`NodeDriver.__init__`
-        """
-        super(BaseGandiDriver, self).__init__(*args, **kwargs)
-
-    def _resource_info(self, type, id):
-        try:
-            obj = self.connection.request('hosting.%s.info' % type, int(id))
-            return obj.object
-        except Exception:
-            e = sys.exc_info()[1]
-            raise GandiException(1003, e)
-        return None
-
-    def _node_info(self, id):
-        return self._resource_info('vm', id)
-
-    def _volume_info(self, id):
-        return self._resource_info('disk', id)
-
-    # Generic methods for driver
-    def _to_node(self, vm):
-        return Node(
-            id=vm['id'],
-            name=vm['hostname'],
-            state=NODE_STATE_MAP.get(
-                vm['state'],
-                NodeState.UNKNOWN
-            ),
-            public_ips=vm.get('ips', []),
-            private_ips=[],
-            driver=self,
-            extra={
-                'ai_active': vm.get('ai_active'),
-                'datacenter_id': vm.get('datacenter_id'),
-                'description': vm.get('description')
-            }
-        )
-
-    def _to_nodes(self, vms):
-        return [self._to_node(v) for v in vms]
-
-    def _to_volume(self, disk):
-        extra = {'can_snapshot': disk['can_snapshot']}
-        return StorageVolume(
-            id=disk['id'],
-            name=disk['name'],
-            size=int(disk['size']),
-            driver=self,
-            extra=extra)
-
-    def _to_volumes(self, disks):
-        return [self._to_volume(d) for d in disks]
-
-    def list_nodes(self):
-        """
-        Return a list of nodes in the current zone or all zones.
-
-        :return:  List of Node objects
-        :rtype:   ``list`` of :class:`Node`
-        """
-        vms = self.connection.request('hosting.vm.list').object
-        ips = self.connection.request('hosting.ip.list').object
-        for vm in vms:
-            vm['ips'] = []
-            for ip in ips:
-                if vm['ifaces_id'][0] == ip['iface_id']:
-                    ip = ip.get('ip', None)
-                    if ip:
-                        vm['ips'].append(ip)
-
-        nodes = self._to_nodes(vms)
-        return nodes
-
-    def ex_get_node(self, node_id):
-        """
-        Return a Node object based on a node id.
-
-        :param  name: The ID of the node
-        :type   name: ``int``
-
-        :return:  A Node object for the node
-        :rtype:   :class:`Node`
-        """
-        vm = self.connection.request('hosting.vm.info', int(node_id)).object
-        ips = self.connection.request('hosting.ip.list').object
-        vm['ips'] = []
-        for ip in ips:
-            if vm['ifaces_id'][0] == ip['iface_id']:
-                ip = ip.get('ip', None)
-                if ip:
-                    vm['ips'].append(ip)
-        node = self._to_node(vm)
-        return node
-
-    def reboot_node(self, node):
-        """
-        Reboot a node.
-
-        :param  node: Node to be rebooted
-        :type   node: :class:`Node`
-
-        :return:  True if successful, False if not
-        :rtype:   ``bool``
-        """
-        op = self.connection.request('hosting.vm.reboot', int(node.id))
-        self._wait_operation(op.object['id'])
-        vm = self._node_info(int(node.id))
-        if vm['state'] == 'running':
-            return True
-        return False
-
-    def destroy_node(self, node):
-        """
-        Destroy a node.
-
-        :param  node: Node object to destroy
-        :type   node: :class:`Node`
-
-        :return:  True if successful
-        :rtype:   ``bool``
-        """
-        vm = self._node_info(node.id)
-        if vm['state'] == 'running':
-            # Send vm_stop and wait for accomplish
-            op_stop = self.connection.request('hosting.vm.stop', int(node.id))
-            if not self._wait_operation(op_stop.object['id']):
-                raise GandiException(1010, 'vm.stop failed')
-            # Delete
-        op = self.connection.request('hosting.vm.delete', int(node.id))
-        if self._wait_operation(op.object['id']):
-            return True
-        return False
-
-    def deploy_node(self, **kwargs):
-        """
-        deploy_node is not implemented for gandi driver
-
-        :rtype: ``bool``
-        """
-        raise NotImplementedError(
-            'deploy_node not implemented for gandi driver')
-
-    def create_node(self, **kwargs):
-        """
-        Create a new Gandi node
-
-        :keyword    name:   String with a name for this new node (required)
-        :type       name:   ``str``
-
-        :keyword    image:  OS Image to boot on node. (required)
-        :type       image:  :class:`NodeImage`
-
-        :keyword    location: Which data center to create a node in. If empty,
-                              undefined behavior will be selected. (optional)
-        :type       location: :class:`NodeLocation`
-
-        :keyword    size:   The size of resources allocated to this node.
-                            (required)
-        :type       size:   :class:`NodeSize`
-
-        :keyword    login: user name to create for login on machine (required)
-        :type       login: ``str``
-
-        :keyword    password: password for user that'll be created (required)
-        :type       password: ``str``
-
-        :keyword    inet_family: version of ip to use, default 4 (optional)
-        :type       inet_family: ``int``
-
-        :keyword    keypairs: IDs of keypairs or Keypairs object
-        :type       keypairs: list of ``int`` or :class:`.KeyPair`
-
-        :rtype: :class:`Node`
-        """
-
-        if not kwargs.get('login') and not kwargs.get('keypairs'):
-            raise GandiException(1020, "Login and password or ssh keypair "
-                                 "must be defined for node creation")
-
-        location = kwargs.get('location')
-        if location and isinstance(location, NodeLocation):
-            dc_id = int(location.id)
-        else:
-            raise GandiException(
-                1021, 'location must be a subclass of NodeLocation')
-
-        size = kwargs.get('size')
-        if not size and not isinstance(size, NodeSize):
-            raise GandiException(
-                1022, 'size must be a subclass of NodeSize')
-
-        keypairs = kwargs.get('keypairs', [])
-        keypair_ids = [
-            k if isinstance(k, int) else k.extra['id']
-            for k in keypairs
-        ]
-
-        # If size name is in INSTANCE_TYPE we use new rating model
-        instance = INSTANCE_TYPES.get(size.id)
-        cores = instance['cpu'] if instance else int(size.id)
-
-        src_disk_id = int(kwargs['image'].id)
-
-        disk_spec = {
-            'datacenter_id': dc_id,
-            'name': 'disk_%s' % kwargs['name']
-        }
-
-        vm_spec = {
-            'datacenter_id': dc_id,
-            'hostname': kwargs['name'],
-            'memory': int(size.ram),
-            'cores': cores,
-            'bandwidth': int(size.bandwidth),
-            'ip_version': kwargs.get('inet_family', 4),
-        }
-
-        if kwargs.get('login') and kwargs.get('password'):
-            vm_spec.update({
-                'login': kwargs['login'],
-                'password': kwargs['password'],  # TODO : use NodeAuthPassword
-            })
-        if keypair_ids:
-            vm_spec['keys'] = keypair_ids
-
-        # Call create_from helper api. Return 3 operations : disk_create,
-        # iface_create,vm_create
-        (op_disk, op_iface, op_vm) = self.connection.request(
-            'hosting.vm.create_from',
-            vm_spec, disk_spec, src_disk_id
-        ).object
-
-        # We wait for vm_create to finish
-        if self._wait_operation(op_vm['id']):
-            # after successful operation, get ip information
-            # thru first interface
-            node = self._node_info(op_vm['vm_id'])
-            ifaces = node.get('ifaces')
-            if len(ifaces) > 0:
-                ips = ifaces[0].get('ips')
-                if len(ips) > 0:
-                    node['ip'] = ips[0]['ip']
-            return self._to_node(node)
-
-        return None
-
-    def _to_image(self, img):
-        return NodeImage(
-            id=img['disk_id'],
-            name=img['label'],
-            driver=self.connection.driver
-        )
-
-    def list_images(self, location=None):
-        """
-        Return a list of image objects.
-
-        :keyword    location: Which data center to filter a images in.
-        :type       location: :class:`NodeLocation`
-
-        :return:  List of GCENodeImage objects
-        :rtype:   ``list`` of :class:`GCENodeImage`
-        """
-        try:
-            if location:
-                filtering = {'datacenter_id': int(location.id)}
-            else:
-                filtering = {}
-            images = self.connection.request('hosting.image.list', filtering)
-            return [self._to_image(i) for i in images.object]
-        except Exception:
-            e = sys.exc_info()[1]
-            raise GandiException(1011, e)
-
-    def _to_size(self, id, size):
-        return NodeSize(
-            id=id,
-            name='%s cores' % id,
-            ram=size['memory'],
-            disk=size['disk'],
-            bandwidth=size['bandwidth'],
-            price=(self._get_size_price(size_id='1') * id),
-            driver=self.connection.driver,
-        )
-
-    def _instance_type_to_size(self, instance):
-        return NodeSize(
-            id=instance['id'],
-            name=instance['name'],
-            ram=instance['memory'],
-            disk=instance['disk'],
-            bandwidth=instance['bandwidth'],
-            price=self._get_size_price(size_id=instance['id']),
-            driver=self.connection.driver,
-        )
-
-    def list_instance_type(self, location=None):
-        return [self._instance_type_to_size(instance)
-                for name, instance in INSTANCE_TYPES.items()]
-
-    def list_sizes(self, location=None):
-        """
-        Return a list of sizes (machineTypes) in a zone.
-
-        :keyword  location: Which data center to filter a sizes in.
-        :type     location: :class:`NodeLocation` or ``None``
-
-        :return:  List of NodeSize objects
-        :rtype:   ``list`` of :class:`NodeSize`
-        """
-        account = self.connection.request('hosting.account.info').object
-        if account.get('rating_enabled'):
-            # This account use new rating model
-            return self.list_instance_type(location)
-        # Look for available shares, and return a list of share_definition
-        available_res = account['resources']['available']
-
-        if available_res['shares'] == 0:
-            return None
-        else:
-            share_def = account['share_definition']
-            available_cores = available_res['cores']
-            # 0.75 core given when creating a server
-            max_core = int(available_cores + 0.75)
-            shares = []
-            if available_res['servers'] < 1:
-                # No server quota, no way
-                return shares
-            for i in range(1, max_core + 1):
-                share = {id: i}
-                share_is_available = True
-                for k in ['memory', 'disk', 'bandwidth']:
-                    if share_def[k] * i > available_res[k]:
-                        # We run out for at least one resource inside
-                        share_is_available = False
-                    else:
-                        share[k] = share_def[k] * i
-                if share_is_available:
-                    nb_core = i
-                    shares.append(self._to_size(nb_core, share))
-            return shares
-
-    def _to_loc(self, loc):
-        return NodeLocation(
-            id=loc['id'],
-            name=loc['name'],
-            country=loc['country'],
-            driver=self
-        )
-
-    def list_locations(self):
-        """
-        Return a list of locations (datacenters).
-
-        :return: List of NodeLocation objects
-        :rtype: ``list`` of :class:`NodeLocation`
-        """
-        res = self.connection.request('hosting.datacenter.list')
-        return [self._to_loc(l) for l in res.object]
-
-    def list_volumes(self):
-        """
-        Return a list of volumes.
-
-        :return: A list of volume objects.
-        :rtype: ``list`` of :class:`StorageVolume`
-        """
-        res = self.connection.request('hosting.disk.list', {})
-        return self._to_volumes(res.object)
-
-    def ex_get_volume(self, volume_id):
-        """
-        Return a Volume object based on a volume ID.
-
-        :param  volume_id: The ID of the volume
-        :type   volume_id: ``int``
-
-        :return:  A StorageVolume object for the volume
-        :rtype:   :class:`StorageVolume`
-        """
-        res = self.connection.request('hosting.disk.info', volume_id)
-        return self._to_volume(res.object)
-
-    def create_volume(self, size, name, location=None, snapshot=None):
-        """
-        Create a volume (disk).
-
-        :param  size: Size of volume to create (in GB).
-        :type   size: ``int``
-
-        :param  name: Name of volume to create
-        :type   name: ``str``
-
-        :keyword  location: Location (zone) to create the volume in
-        :type     location: :class:`NodeLocation` or ``None``
-
-        :keyword  snapshot: Snapshot to create image from
-        :type     snapshot: :class:`Snapshot`
-
-        :return:  Storage Volume object
-        :rtype:   :class:`StorageVolume`
-        """
-        disk_param = {
-            'name': name,
-            'size': int(size),
-            'datacenter_id': int(location.id)
-        }
-        if snapshot:
-            op = self.connection.request('hosting.disk.create_from',
-                                         disk_param, int(snapshot.id))
-        else:
-            op = self.connection.request('hosting.disk.create', disk_param)
-        if self._wait_operation(op.object['id']):
-            disk = self._volume_info(op.object['disk_id'])
-            return self._to_volume(disk)
-        return None
-
-    def attach_volume(self, node, volume, device=None):
-        """
-        Attach a volume to a node.
-
-        :param  node: The node to attach the volume to
-        :type   node: :class:`Node`
-
-        :param  volume: The volume to attach.
-        :type   volume: :class:`StorageVolume`
-
-        :keyword  device: Not used in this cloud.
-        :type     device: ``None``
-
-        :return:  True if successful
-        :rtype:   ``bool``
-        """
-        op = self.connection.request('hosting.vm.disk_attach',
-                                     int(node.id), int(volume.id))
-        if self._wait_operation(op.object['id']):
-            return True
-        return False
-
-    def detach_volume(self, node, volume):
-        """
-        Detaches a volume from a node.
-
-        :param      node: Node which should be used
-        :type       node: :class:`Node`
-
-        :param      volume: Volume to be detached
-        :type       volume: :class:`StorageVolume`
-
-        :rtype: ``bool``
-        """
-        op = self.connection.request('hosting.vm.disk_detach',
-                                     int(node.id), int(volume.id))
-        if self._wait_operation(op.object['id']):
-            return True
-        return False
-
-    def destroy_volume(self, volume):
-        """
-        Destroy a volume.
-
-        :param  volume: Volume object to destroy
-        :type   volume: :class:`StorageVolume`
-
-        :return:  True if successful
-        :rtype:   ``bool``
-        """
-        op = self.connection.request('hosting.disk.delete', int(volume.id))
-        if self._wait_operation(op.object['id']):
-            return True
-        return False
-
-    def _to_iface(self, iface):
-        ips = []
-        for ip in iface.get('ips', []):
-            new_ip = IPAddress(
-                ip['id'],
-                NODE_STATE_MAP.get(
-                    ip['state'],
-                    NodeState.UNKNOWN
-                ),
-                ip['ip'],
-                self.connection.driver,
-                version=ip.get('version'),
-                extra={'reverse': ip['reverse']}
-            )
-            ips.append(new_ip)
-        return NetworkInterface(
-            iface['id'],
-            NODE_STATE_MAP.get(
-                iface['state'],
-                NodeState.UNKNOWN
-            ),
-            mac_address=None,
-            driver=self.connection.driver,
-            ips=ips,
-            node_id=iface.get('vm_id'),
-            extra={'bandwidth': iface['bandwidth']},
-        )
-
-    def _to_ifaces(self, ifaces):
-        return [self._to_iface(i) for i in ifaces]
-
-    def ex_list_interfaces(self):
-        """
-        Specific method to list network interfaces
-
-        :rtype: ``list`` of :class:`GandiNetworkInterface`
-        """
-        ifaces = self.connection.request('hosting.iface.list').object
-        ips = self.connection.request('hosting.ip.list').object
-        for iface in ifaces:
-            iface['ips'] = list(
-                filter(lambda i: i['iface_id'] == iface['id'], ips))
-        return self._to_ifaces(ifaces)
-
-    def _to_disk(self, element):
-        disk = Disk(
-            id=element['id'],
-            state=NODE_STATE_MAP.get(
-                element['state'],
-                NodeState.UNKNOWN
-            ),
-            name=element['name'],
-            driver=self.connection.driver,
-            size=element['size'],
-            extra={'can_snapshot': element['can_snapshot']}
-        )
-        return disk
-
-    def _to_disks(self, elements):
-        return [self._to_disk(el) for el in elements]
-
-    def ex_list_disks(self):
-        """
-        Specific method to list all disk
-
-        :rtype: ``list`` of :class:`GandiDisk`
-        """
-        res = self.connection.request('hosting.disk.list', {})
-        return self._to_disks(res.object)
-
-    def ex_node_attach_disk(self, node, disk):
-        """
-        Specific method to attach a disk to a node
-
-        :param      node: Node which should be used
-        :type       node: :class:`Node`
-
-        :param      disk: Disk which should be used
-        :type       disk: :class:`GandiDisk`
-
-        :rtype: ``bool``
-        """
-        op = self.connection.request('hosting.vm.disk_attach',
-                                     int(node.id), int(disk.id))
-        if self._wait_operation(op.object['id']):
-            return True
-        return False
-
-    def ex_node_detach_disk(self, node, disk):
-        """
-        Specific method to detach a disk from a node
-
-        :param      node: Node which should be used
-        :type       node: :class:`Node`
-
-        :param      disk: Disk which should be used
-        :type       disk: :class:`GandiDisk`
-
-        :rtype: ``bool``
-        """
-        op = self.connection.request('hosting.vm.disk_detach',
-                                     int(node.id), int(disk.id))
-        if self._wait_operation(op.object['id']):
-            return True
-        return False
-
-    def ex_node_attach_interface(self, node, iface):
-        """
-        Specific method to attach an interface to a node
-
-        :param      node: Node which should be used
-        :type       node: :class:`Node`
-
-        :param      iface: Network interface which should be used
-        :type       iface: :class:`GandiNetworkInterface`
-
-        :rtype: ``bool``
-        """
-        op = self.connection.request('hosting.vm.iface_attach',
-                                     int(node.id), int(iface.id))
-        if self._wait_operation(op.object['id']):
-            return True
-        return False
-
-    def ex_node_detach_interface(self, node, iface):
-        """
-        Specific method to detach an interface from a node
-
-        :param      node: Node which should be used
-        :type       node: :class:`Node`
-
-        :param      iface: Network interface which should be used
-        :type       iface: :class:`GandiNetworkInterface`
-
-        :rtype: ``bool``
-        """
-        op = self.connection.request('hosting.vm.iface_detach',
-                                     int(node.id), int(iface.id))
-        if self._wait_operation(op.object['id']):
-            return True
-        return False
-
-    def ex_snapshot_disk(self, disk, name=None):
-        """
-        Specific method to make a snapshot of a disk
-
-        :param      disk: Disk which should be used
-        :type       disk: :class:`GandiDisk`
-
-        :param      name: Name which should be used
-        :type       name: ``str``
-
-        :rtype: ``bool``
-        """
-        if not disk.extra.get('can_snapshot'):
-            raise GandiException(1021, 'Disk %s can\'t snapshot' % disk.id)
-        if not name:
-            suffix = datetime.today().strftime('%Y%m%d')
-            name = 'snap_%s' % (suffix)
-        op = self.connection.request(
-            'hosting.disk.create_from',
-            {'name': name, 'type': 'snapshot', },
-            int(disk.id),
-        )
-        if self._wait_operation(op.object['id']):
-            return True
-        return False
-
-    def ex_update_disk(self, disk, new_size=None, new_name=None):
-        """Specific method to update size or name of a disk
-        WARNING: if a server is attached it'll be rebooted
-
-        :param      disk: Disk which should be used
-        :type       disk: :class:`GandiDisk`
-
-        :param      new_size: New size
-        :type       new_size: ``int``
-
-        :param      new_name: New name
-        :type       new_name: ``str``
-
-        :rtype: ``bool``
-        """
-        params = {}
-        if new_size:
-            params.update({'size': new_size})
-        if new_name:
-            params.update({'name': new_name})
-        op = self.connection.request('hosting.disk.update',
-                                     int(disk.id),
-                                     params)
-        if self._wait_operation(op.object['id']):
-            return True
-        return False
-
-    def _to_key_pair(self, data):
-        key_pair = KeyPair(name=data['name'],
-                           fingerprint=data['fingerprint'],
-                           public_key=data.get('value', None),
-                           private_key=data.get('privatekey', None),
-                           driver=self, extra={'id': data['id']})
-        return key_pair
-
-    def _to_key_pairs(self, data):
-        return [self._to_key_pair(k) for k in data]
-
-    def list_key_pairs(self):
-        """
-        List registered key pairs.
-
-        :return:   A list of key par objects.
-        :rtype:   ``list`` of :class:`libcloud.compute.base.KeyPair`
-        """
-        kps = self.connection.request('hosting.ssh.list').object
-        return self._to_key_pairs(kps)
-
-    def get_key_pair(self, name):
-        """
-        Retrieve a single key pair.
-
-        :param name: Name of the key pair to retrieve.
-        :type name: ``str``
-
-        :rtype: :class:`.KeyPair`
-        """
-        filter_params = {'name': name}
-        kps = self.connection.request('hosting.ssh.list', filter_params).object
-        return self._to_key_pair(kps[0])
-
-    def import_key_pair_from_string(self, name, key_material):
-        """
-        Create a new key pair object.
-
-        :param name: Key pair name.
-        :type name: ``str``
-
-        :param key_material: Public key material.
-        :type key_material: ``str``
-
-        :return: Imported key pair object.
-        :rtype: :class:`.KeyPair`
-        """
-        params = {'name': name, 'value': key_material}
-        kp = self.connection.request('hosting.ssh.create', params).object
-        return self._to_key_pair(kp)
-
-    def delete_key_pair(self, key_pair):
-        """
-        Delete an existing key pair.
-
-        :param key_pair: Key pair object or ID.
-        :type key_pair: :class.KeyPair` or ``int``
-
-        :return:   True of False based on success of Keypair deletion
-        :rtype:    ``bool``
-        """
-        key_id = key_pair if isinstance(key_pair, int) \
-            else key_pair.extra['id']
-        success = self.connection.request('hosting.ssh.delete', key_id).object
-        return success

Reply via email to