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/10/05 07:38:07 UTC

[17/22] libcloud git commit: Remove DigitalOcean v1 driver as it has reached EOL.

Remove DigitalOcean v1 driver as it has reached EOL.


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/f311aaf2
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/f311aaf2
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/f311aaf2

Branch: refs/heads/trunk
Commit: f311aaf2a2693b442a8143b565b4178ee625a0ac
Parents: d9745a0
Author: Andrew Starr-Bochicchio <a....@gmail.com>
Authored: Tue Oct 4 21:18:10 2016 -0400
Committer: Anthony Shaw <an...@apache.org>
Committed: Wed Oct 5 18:37:03 2016 +1100

----------------------------------------------------------------------
 libcloud/common/digitalocean.py                 |  68 +-----
 libcloud/compute/drivers/digitalocean.py        | 231 +------------------
 libcloud/test/common/test_digitalocean_v1.py    |  82 -------
 .../fixtures/digitalocean_v1/create_node.json   |   1 -
 .../fixtures/digitalocean_v1/destroy_node.json  |   1 -
 .../compute/fixtures/digitalocean_v1/error.txt  |   1 -
 .../digitalocean_v1/error_invalid_image.json    |   1 -
 .../digitalocean_v1/ex_create_ssh_key.json      |   1 -
 .../digitalocean_v1/ex_destroy_ssh_key.json     |   1 -
 .../digitalocean_v1/ex_list_ssh_keys.json       |   1 -
 .../digitalocean_v1/ex_rename_node.json         |   1 -
 .../fixtures/digitalocean_v1/list_images.json   | 145 ------------
 .../digitalocean_v1/list_locations.json         |   1 -
 .../fixtures/digitalocean_v1/list_nodes.json    |   1 -
 .../digitalocean_v1/list_nodes_empty.json       |   1 -
 .../digitalocean_v1/list_nodes_page_2.json      |  95 --------
 .../fixtures/digitalocean_v1/list_sizes.json    |   1 -
 .../fixtures/digitalocean_v1/reboot_node.json   |   1 -
 libcloud/test/compute/test_digitalocean_v1.py   | 206 -----------------
 libcloud/test/compute/test_digitalocean_v2.py   |   5 +
 20 files changed, 18 insertions(+), 827 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/f311aaf2/libcloud/common/digitalocean.py
----------------------------------------------------------------------
diff --git a/libcloud/common/digitalocean.py b/libcloud/common/digitalocean.py
index 2e6f329..be452bb 100644
--- a/libcloud/common/digitalocean.py
+++ b/libcloud/common/digitalocean.py
@@ -16,60 +16,32 @@
 """
 Common settings and connection objects for DigitalOcean Cloud
 """
-import warnings
 
 from libcloud.utils.py3 import httplib, parse_qs, urlparse
 
 from libcloud.common.base import BaseDriver
-from libcloud.common.base import ConnectionUserAndKey, ConnectionKey
+from libcloud.common.base import ConnectionKey
 from libcloud.common.base import JsonResponse
-from libcloud.common.types import InvalidCredsError
+from libcloud.common.types import LibcloudError, InvalidCredsError
 
 __all__ = [
-    'DigitalOcean_v1_Response',
-    'DigitalOcean_v1_Connection',
     'DigitalOcean_v2_Response',
     'DigitalOcean_v2_Connection',
     'DigitalOceanBaseDriver'
 ]
 
 
-class DigitalOcean_v1_Response(JsonResponse):
-    def parse_error(self):
-        if self.status == httplib.FOUND and '/api/error' in self.body:
-            # Hacky, but DigitalOcean error responses are awful
-            raise InvalidCredsError(self.body)
-        elif self.status == httplib.UNAUTHORIZED:
-            body = self.parse_body()
-            raise InvalidCredsError(body['message'])
-        else:
-            body = self.parse_body()
-
-            if 'error_message' in body:
-                error = '%s (code: %s)' % (body['error_message'], self.status)
-            else:
-                error = body
-            return error
-
-
-class DigitalOcean_v1_Connection(ConnectionUserAndKey):
+class DigitalOcean_v1_Error(LibcloudError):
     """
-    Connection class for the DigitalOcean (v1) driver.
+    Exception for when attempting to use version 1
+    of the DigitalOcean API which is no longer
+    supported.
     """
 
-    host = 'api.digitalocean.com'
-    responseCls = DigitalOcean_v1_Response
-
-    def add_default_params(self, params):
-        """
-        Add parameters that are necessary for every request
-
-        This method adds ``client_id`` and ``api_key`` to
-        the request.
-        """
-        params['client_id'] = self.user_id
-        params['api_key'] = self.key
-        return params
+    def __init__(self, value=('Version 1 of the DigitalOcean API reached end'
+                 ' of life on November 9, 2015. Please use the v2 driver.'),
+                 driver=None):
+        super(DigitalOcean_v1_Error, self).__init__(value, driver=driver)
 
 
 class DigitalOcean_v2_Response(JsonResponse):
@@ -142,9 +114,7 @@ class DigitalOceanBaseDriver(BaseDriver):
     def __new__(cls, key, secret=None, api_version='v2', **kwargs):
         if cls is DigitalOceanBaseDriver:
             if api_version == 'v1' or secret is not None:
-                cls = DigitalOcean_v1_BaseDriver
-                warnings.warn("The v1 API has become deprecated. Please "
-                              "consider utilizing the v2 API.")
+                raise DigitalOcean_v1_Error()
             elif api_version == 'v2':
                 cls = DigitalOcean_v2_BaseDriver
             else:
@@ -169,22 +139,6 @@ class DigitalOceanBaseDriver(BaseDriver):
             '_paginated_requests not implemented for this driver')
 
 
-class DigitalOcean_v1_BaseDriver(DigitalOceanBaseDriver):
-    """
-    DigitalOcean BaseDriver using v1 of the API.
-    """
-    connectionCls = DigitalOcean_v1_Connection
-
-    def ex_get_event(self, event_id):
-        """
-        Get an event object
-
-        :param      event_id: Event id (required)
-        :type       event_id: ``str``
-        """
-        return self.connection.request('/v1/events/%s' % event_id).object
-
-
 class DigitalOcean_v2_BaseDriver(DigitalOceanBaseDriver):
     """
     DigitalOcean BaseDriver using v2 of the API.

http://git-wip-us.apache.org/repos/asf/libcloud/blob/f311aaf2/libcloud/compute/drivers/digitalocean.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/digitalocean.py b/libcloud/compute/drivers/digitalocean.py
index aefa099..dd9836d 100644
--- a/libcloud/compute/drivers/digitalocean.py
+++ b/libcloud/compute/drivers/digitalocean.py
@@ -21,7 +21,7 @@ import warnings
 from libcloud.utils.iso8601 import parse_date
 from libcloud.utils.py3 import httplib
 
-from libcloud.common.digitalocean import DigitalOcean_v1_BaseDriver
+from libcloud.common.digitalocean import DigitalOcean_v1_Error
 from libcloud.common.digitalocean import DigitalOcean_v2_BaseDriver
 from libcloud.common.types import InvalidCredsError
 from libcloud.compute.types import Provider, NodeState
@@ -31,7 +31,6 @@ from libcloud.compute.base import StorageVolume
 
 __all__ = [
     'DigitalOceanNodeDriver',
-    'DigitalOcean_v1_NodeDriver',
     'DigitalOcean_v2_NodeDriver'
 ]
 
@@ -61,13 +60,10 @@ class DigitalOceanNodeDriver(NodeDriver):
     def __new__(cls, key, secret=None, api_version='v2', **kwargs):
         if cls is DigitalOceanNodeDriver:
             if api_version == 'v1' or secret is not None:
-                if secret is None:
-                    raise InvalidCredsError(
-                        'secret missing for v1 authentication')
                 if secret is not None and api_version == 'v2':
                     raise InvalidCredsError(
                         'secret not accepted for v2 authentication')
-                cls = DigitalOcean_v1_NodeDriver
+                raise DigitalOcean_v1_Error()
             elif api_version == 'v2':
                 cls = DigitalOcean_v2_NodeDriver
             else:
@@ -88,229 +84,6 @@ class SSHKey(object):
                 (self.id, self.name, self.pub_key))
 
 
-class DigitalOcean_v1_NodeDriver(DigitalOcean_v1_BaseDriver,
-                                 DigitalOceanNodeDriver):
-    """
-    DigitalOcean NodeDriver using v1 of the API.
-    """
-
-    NODE_STATE_MAP = {'new': NodeState.PENDING,
-                      'off': NodeState.REBOOTING,
-                      'active': NodeState.RUNNING}
-
-    def list_nodes(self):
-        data = self.connection.request('/v1/droplets').object['droplets']
-        return list(map(self._to_node, data))
-
-    def list_locations(self):
-        data = self.connection.request('/v1/regions').object['regions']
-        return list(map(self._to_location, data))
-
-    def list_images(self):
-        data = self.connection.request('/v1/images').object['images']
-        return list(map(self._to_image, data))
-
-    def list_sizes(self):
-        data = self.connection.request('/v1/sizes').object['sizes']
-        return list(map(self._to_size, data))
-
-    def create_node(self, name, size, image, location, ex_ssh_key_ids=None):
-        """
-        Create a node.
-
-        :keyword    ex_ssh_key_ids: A list of ssh key ids which will be added
-                                   to the server. (optional)
-        :type       ex_ssh_key_ids: ``list`` of ``str``
-
-        :return: The newly created node.
-        :rtype: :class:`Node`
-        """
-        params = {'name': name, 'size_id': size.id, 'image_id': image.id,
-                  'region_id': location.id}
-
-        if ex_ssh_key_ids:
-            params['ssh_key_ids'] = ','.join(ex_ssh_key_ids)
-
-        data = self.connection.request('/v1/droplets/new', params=params)
-
-        # TODO: Handle this in the response class
-        status = data.object.get('status', 'OK')
-        if status == 'ERROR':
-            message = data.object.get('message', None)
-            error_message = data.object.get('error_message', message)
-            raise ValueError('Failed to create node: %s' % (error_message))
-
-        return self._to_node(data=data.object['droplet'])
-
-    def reboot_node(self, node):
-        res = self.connection.request('/v1/droplets/%s/reboot/' % (node.id))
-        return res.status == httplib.OK
-
-    def destroy_node(self, node):
-        params = {'scrub_data': '1'}
-        res = self.connection.request('/v1/droplets/%s/destroy/' % (node.id),
-                                      params=params)
-        return res.status == httplib.OK
-
-    def ex_rename_node(self, node, name):
-        params = {'name': name}
-        res = self.connection.request('/v1/droplets/%s/rename/' % (node.id),
-                                      params=params)
-        return res.status == httplib.OK
-
-    def list_key_pairs(self):
-        """
-        List all the available SSH keys.
-
-        :return: Available SSH keys.
-        :rtype: ``list`` of :class:`KeyPair`
-        """
-        data = self.connection.request('/v1/ssh_keys').object['ssh_keys']
-        return list(map(self._to_key_pair, data))
-
-    def ex_list_ssh_keys(self):
-        """
-        List all the available SSH keys.
-        :return: Available SSH keys.
-        :rtype: ``list`` of :class:`SSHKey`
-        """
-        warnings.warn("This method has been deprecated in "
-                      "favor of the list_key_pairs method")
-
-        data = self.connection.request('/v1/ssh_keys').object['ssh_keys']
-        return list(map(self._to_ssh_key, data))
-
-    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`
-        """
-        qkey = [k for k in self.list_key_pairs() if k.name == name][0]
-        data = self.connection.request('/v1/ssh_keys/%s' %
-                                       qkey.extra['id']).object['ssh_key']
-        return self._to_key_pair(data=data)
-
-    # TODO: This adds the ssh_key_pub parameter. This puts the burden of making
-    #      it within the function or on the API. The KeyPair API needs work.
-    def create_key_pair(self, name, ssh_key_pub):
-        """
-        Create a new SSH key.
-
-        :param      name: Key name (required)
-        :type       name: ``str``
-
-        :param      name: Valid public key string (required)
-        :type       name: ``str``
-        """
-        params = {'name': name, 'ssh_pub_key': ssh_key_pub}
-        data = self.connection.request('/v1/ssh_keys/new/', method='GET',
-                                       params=params).object
-        assert 'ssh_key' in data
-        # TODO: libcloud.compute.base.KeyPair.create_key_pair doesn't specify
-        #      a return value. This looks like it should return a KeyPair
-        return self._to_key_pair(data=data['ssh_key'])
-
-    def ex_create_ssh_key(self, name, ssh_key_pub):
-        """
-        Create a new SSH key.
-        :param      name: Key name (required)
-        :type       name: ``str``
-        :param      name: Valid public key string (required)
-        :type       name: ``str``
-        """
-        warnings.warn("This method has been deprecated in "
-                      "favor of the create_key_pair method")
-
-        params = {'name': name, 'ssh_pub_key': ssh_key_pub}
-        data = self.connection.request('/v1/ssh_keys/new/', method='GET',
-                                       params=params).object
-        assert 'ssh_key' in data
-        return self._to_ssh_key(data=data['ssh_key'])
-
-    def delete_key_pair(self, key_pair):
-        """
-        Delete an existing key pair.
-
-        :param key_pair: Key pair object.
-        :type key_pair: :class:`.KeyPair`
-        """
-        res = self.connection.request('/v1/ssh_keys/%s/destroy/' %
-                                      key_pair.extra['id'])
-        # TODO: This looks like it should return bool like the other delete_*
-        return res.status == httplib.OK
-
-    def ex_destroy_ssh_key(self, key_id):
-        """
-        Delete an existing SSH key.
-        :param      key_id: SSH key id (required)
-        :type       key_id: ``str``
-        """
-        warnings.warn(
-            "This method has been deprecated in "
-            "favor of the delete_key_pair method")
-
-        res = self.connection.request('/v1/ssh_keys/%s/destroy/' % (key_id))
-        return res.status == httplib.OK
-
-    def _to_node(self, data):
-        extra_keys = ['backups_active', 'region_id', 'image_id', 'size_id']
-        if 'status' in data:
-            state = self.NODE_STATE_MAP.get(data['status'], NodeState.UNKNOWN)
-        else:
-            state = NodeState.UNKNOWN
-
-        if 'ip_address' in data and data['ip_address'] is not None:
-            public_ips = [data['ip_address']]
-        else:
-            public_ips = []
-
-        extra = {}
-        for key in extra_keys:
-            if key in data:
-                extra[key] = data[key]
-
-        node = Node(id=data['id'], name=data['name'], state=state,
-                    public_ips=public_ips, private_ips=None, extra=extra,
-                    driver=self)
-        return node
-
-    def _to_image(self, data):
-        extra = {'distribution': data['distribution']}
-        return NodeImage(id=data['id'], name=data['name'], extra=extra,
-                         driver=self)
-
-    def _to_location(self, data):
-        return NodeLocation(id=data['id'], name=data['name'], country=None,
-                            driver=self)
-
-    def _to_size(self, data):
-        ram = data['name'].lower()
-
-        if 'mb' in ram:
-            ram = int(ram.replace('mb', ''))
-        elif 'gb' in ram:
-            ram = int(ram.replace('gb', '')) * 1024
-
-        return NodeSize(id=data['id'], name=data['name'], ram=ram, disk=0,
-                        bandwidth=0, price=0, driver=self)
-
-    def _to_key_pair(self, data):
-        try:
-            pubkey = data['ssh_pub_key']
-        except KeyError:
-            pubkey = None
-        return KeyPair(data['name'], public_key=pubkey, fingerprint=None,
-                       driver=self, private_key=None, extra={'id': data['id']})
-
-    def _to_ssh_key(self, data):
-        return SSHKey(id=data['id'], name=data['name'],
-                      pub_key=data.get('ssh_pub_key', None))
-
-
 class DigitalOcean_v2_NodeDriver(DigitalOcean_v2_BaseDriver,
                                  DigitalOceanNodeDriver):
     """

http://git-wip-us.apache.org/repos/asf/libcloud/blob/f311aaf2/libcloud/test/common/test_digitalocean_v1.py
----------------------------------------------------------------------
diff --git a/libcloud/test/common/test_digitalocean_v1.py b/libcloud/test/common/test_digitalocean_v1.py
deleted file mode 100644
index 9e99c7f..0000000
--- a/libcloud/test/common/test_digitalocean_v1.py
+++ /dev/null
@@ -1,82 +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
-
-import sys
-import unittest
-
-from libcloud.common.types import InvalidCredsError
-from libcloud.common.digitalocean import DigitalOceanBaseDriver
-from libcloud.test import LibcloudTestCase, MockHttpTestCase
-from libcloud.test.file_fixtures import FileFixtures
-from libcloud.test.secrets import DIGITALOCEAN_v1_PARAMS
-from libcloud.utils.py3 import httplib
-
-
-class DigitalOceanTests(LibcloudTestCase):
-
-    def setUp(self):
-        DigitalOceanBaseDriver.connectionCls.conn_classes = \
-            (None, DigitalOceanMockHttp)
-        DigitalOceanMockHttp.type = None
-        self.driver = DigitalOceanBaseDriver(*DIGITALOCEAN_v1_PARAMS)
-
-    def test_authentication(self):
-        DigitalOceanMockHttp.type = 'UNAUTHORIZED'
-        self.assertRaises(InvalidCredsError, self.driver.ex_get_event,
-                          '12345670')
-
-    def test_ex_account_info(self):
-        self.assertRaises(NotImplementedError, self.driver.ex_account_info)
-
-    def test_ex_list_events(self):
-        self.assertRaises(NotImplementedError, self.driver.ex_list_events)
-
-    def test_ex_get_event(self):
-        action = self.driver.ex_get_event('12345670')
-        self.assertEqual(action["status"], "OK")
-        self.assertEqual(action["event"]["id"], 12345670)
-        self.assertEqual(action["event"]["event_type_id"], 1)
-
-    def test__paginated_request(self):
-        self.assertRaises(NotImplementedError, self.driver._paginated_request,
-                          '/v1/anything', 'anything')
-
-
-class DigitalOceanMockHttp(MockHttpTestCase):
-    fixtures = FileFixtures('common', 'digitalocean')
-
-    response = {
-        None: httplib.OK,
-        'CREATE': httplib.CREATED,
-        'DELETE': httplib.NO_CONTENT,
-        'EMPTY': httplib.OK,
-        'NOT_FOUND': httplib.NOT_FOUND,
-        'UNAUTHORIZED': httplib.UNAUTHORIZED,
-        'UPDATE': httplib.OK
-    }
-
-    def _v1_events_12345670_UNAUTHORIZED(self, method, url, body, headers):
-        body = self.fixtures.load(
-            '_v1_events_12345670_UNAUTHORIZED.json')
-        return (self.response[self.type], body, {},
-                httplib.responses[self.response[self.type]])
-
-    def _v1_events_12345670(self, method, url, body, headers):
-        body = self.fixtures.load('_v1_events_12345670.json')
-        return (self.response[self.type], body, {},
-                httplib.responses[self.response[self.type]])
-
-
-if __name__ == '__main__':
-    sys.exit(unittest.main())

http://git-wip-us.apache.org/repos/asf/libcloud/blob/f311aaf2/libcloud/test/compute/fixtures/digitalocean_v1/create_node.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/digitalocean_v1/create_node.json b/libcloud/test/compute/fixtures/digitalocean_v1/create_node.json
deleted file mode 100644
index acddc08..0000000
--- a/libcloud/test/compute/fixtures/digitalocean_v1/create_node.json
+++ /dev/null
@@ -1 +0,0 @@
-{"status":"OK","droplet":{"id":119461,"name":"test-2","image_id":1601,"size_id":66,"event_id":919341}}

http://git-wip-us.apache.org/repos/asf/libcloud/blob/f311aaf2/libcloud/test/compute/fixtures/digitalocean_v1/destroy_node.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/digitalocean_v1/destroy_node.json b/libcloud/test/compute/fixtures/digitalocean_v1/destroy_node.json
deleted file mode 100644
index bae818d..0000000
--- a/libcloud/test/compute/fixtures/digitalocean_v1/destroy_node.json
+++ /dev/null
@@ -1 +0,0 @@
-{"status":"OK","event_id":918910}

http://git-wip-us.apache.org/repos/asf/libcloud/blob/f311aaf2/libcloud/test/compute/fixtures/digitalocean_v1/error.txt
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/digitalocean_v1/error.txt b/libcloud/test/compute/fixtures/digitalocean_v1/error.txt
deleted file mode 100644
index 0e90e51..0000000
--- a/libcloud/test/compute/fixtures/digitalocean_v1/error.txt
+++ /dev/null
@@ -1 +0,0 @@
-<html><body>You are being <a href="https://www.digitalocean.com/api/error">redirected</a>.</body></html>

http://git-wip-us.apache.org/repos/asf/libcloud/blob/f311aaf2/libcloud/test/compute/fixtures/digitalocean_v1/error_invalid_image.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/digitalocean_v1/error_invalid_image.json b/libcloud/test/compute/fixtures/digitalocean_v1/error_invalid_image.json
deleted file mode 100644
index e1ccb4f..0000000
--- a/libcloud/test/compute/fixtures/digitalocean_v1/error_invalid_image.json
+++ /dev/null
@@ -1 +0,0 @@
-{"status":"ERROR","error_message":"You specified an invalid image for Droplet creation.","message":"You specified an invalid image for Droplet creation."}

http://git-wip-us.apache.org/repos/asf/libcloud/blob/f311aaf2/libcloud/test/compute/fixtures/digitalocean_v1/ex_create_ssh_key.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/digitalocean_v1/ex_create_ssh_key.json b/libcloud/test/compute/fixtures/digitalocean_v1/ex_create_ssh_key.json
deleted file mode 100644
index 029cab2..0000000
--- a/libcloud/test/compute/fixtures/digitalocean_v1/ex_create_ssh_key.json
+++ /dev/null
@@ -1 +0,0 @@
-{"status":"OK","ssh_key":{"id":7717,"name":"test1","ssh_pub_key":"aaq"}}

http://git-wip-us.apache.org/repos/asf/libcloud/blob/f311aaf2/libcloud/test/compute/fixtures/digitalocean_v1/ex_destroy_ssh_key.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/digitalocean_v1/ex_destroy_ssh_key.json b/libcloud/test/compute/fixtures/digitalocean_v1/ex_destroy_ssh_key.json
deleted file mode 100644
index 12d1b59..0000000
--- a/libcloud/test/compute/fixtures/digitalocean_v1/ex_destroy_ssh_key.json
+++ /dev/null
@@ -1 +0,0 @@
-{"status":"OK"}

http://git-wip-us.apache.org/repos/asf/libcloud/blob/f311aaf2/libcloud/test/compute/fixtures/digitalocean_v1/ex_list_ssh_keys.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/digitalocean_v1/ex_list_ssh_keys.json b/libcloud/test/compute/fixtures/digitalocean_v1/ex_list_ssh_keys.json
deleted file mode 100644
index 1111976..0000000
--- a/libcloud/test/compute/fixtures/digitalocean_v1/ex_list_ssh_keys.json
+++ /dev/null
@@ -1 +0,0 @@
-{"status":"OK","ssh_keys":[{"id":7717,"name":"test1"}]}

http://git-wip-us.apache.org/repos/asf/libcloud/blob/f311aaf2/libcloud/test/compute/fixtures/digitalocean_v1/ex_rename_node.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/digitalocean_v1/ex_rename_node.json b/libcloud/test/compute/fixtures/digitalocean_v1/ex_rename_node.json
deleted file mode 100644
index bae818d..0000000
--- a/libcloud/test/compute/fixtures/digitalocean_v1/ex_rename_node.json
+++ /dev/null
@@ -1 +0,0 @@
-{"status":"OK","event_id":918910}

http://git-wip-us.apache.org/repos/asf/libcloud/blob/f311aaf2/libcloud/test/compute/fixtures/digitalocean_v1/list_images.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/digitalocean_v1/list_images.json b/libcloud/test/compute/fixtures/digitalocean_v1/list_images.json
deleted file mode 100644
index 007a57d..0000000
--- a/libcloud/test/compute/fixtures/digitalocean_v1/list_images.json
+++ /dev/null
@@ -1,145 +0,0 @@
-{
-    "status": "OK",
-    "images": [
-        {
-            "id": 1601,
-            "name": "CentOS 5.8 x64",
-            "distribution": "CentOS"
-        },
-        {
-            "id": 1602,
-            "name": "CentOS 5.8 x32",
-            "distribution": "CentOS"
-        },
-        {
-            "id": 1605,
-            "name": "CentOS 6.0 x32",
-            "distribution": "CentOS"
-        },
-        {
-            "id": 1606,
-            "name": "Fedora 15 x64",
-            "distribution": "Fedora"
-        },
-        {
-            "id": 1609,
-            "name": "Ubuntu 11.10 x32 Server",
-            "distribution": "Ubuntu"
-        },
-        {
-            "id": 1611,
-            "name": "CentOS 6.2 x64",
-            "distribution": "CentOS"
-        },
-        {
-            "id": 1615,
-            "name": "Fedora 16 x64 Server",
-            "distribution": "Fedora"
-        },
-        {
-            "id": 1618,
-            "name": "Fedora 16 x64 Desktop",
-            "distribution": "Fedora"
-        },
-        {
-            "id": 2676,
-            "name": "Ubuntu 12.04 x64 Server",
-            "distribution": "Ubuntu"
-        },
-        {
-            "id": 12573,
-            "name": "Debian 6.0 x64",
-            "distribution": "Debian"
-        },
-        {
-            "id": 12574,
-            "name": "CentOS 6.3 x64",
-            "distribution": "CentOS"
-        },
-        {
-            "id": 12575,
-            "name": "Debian 6.0 x32",
-            "distribution": "Debian"
-        },
-        {
-            "id": 12578,
-            "name": "CentOS 6.3 x32",
-            "distribution": "CentOS"
-        },
-        {
-            "id": 14097,
-            "name": "Ubuntu 10.04 x64 Server",
-            "distribution": "Ubuntu"
-        },
-        {
-            "id": 14098,
-            "name": "Ubuntu 10.04 x32 Server",
-            "distribution": "Ubuntu"
-        },
-        {
-            "id": 14218,
-            "name": "Ubuntu 12.04 x64 Desktop",
-            "distribution": "Ubuntu"
-        },
-        {
-            "id": 25306,
-            "name": "Ubuntu 12.10 x32 Server",
-            "distribution": "Ubuntu"
-        },
-        {
-            "id": 25485,
-            "name": "Ubuntu 12.10 x32 Desktop",
-            "distribution": "Ubuntu"
-        },
-        {
-            "id": 25489,
-            "name": "Ubuntu 12.10 x64 Server",
-            "distribution": "Ubuntu"
-        },
-        {
-            "id": 25493,
-            "name": "Ubuntu 12.10 x64 Desktop",
-            "distribution": "Ubuntu"
-        },
-        {
-            "id": 32387,
-            "name": "Fedora 17 x32 Server",
-            "distribution": "Fedora"
-        },
-        {
-            "id": 32399,
-            "name": "Fedora 17 x32 Desktop",
-            "distribution": "Fedora"
-        },
-        {
-            "id": 32419,
-            "name": "Fedora 17 x64 Desktop",
-            "distribution": "Fedora"
-        },
-        {
-            "id": 32428,
-            "name": "Fedora 17 x64 Server",
-            "distribution": "Fedora"
-        },
-        {
-            "id": 42735,
-            "name": "Ubuntu 12.04 x32 Server",
-            "distribution": "Ubuntu"
-        },
-        {
-            "id": 43458,
-            "name": "Ubuntu 11.04x64 Server",
-            "distribution": "Ubuntu"
-        },
-        {
-            "id": 43462,
-            "name": "Ubuntu 11.04x32 Desktop",
-            "distribution": "Ubuntu"
-        },
-        {
-            "id": 46964,
-            "name": "LAMP on Ubuntu 12.04",
-            "distribution": "Ubuntu"
-        }
-    ]
-}

http://git-wip-us.apache.org/repos/asf/libcloud/blob/f311aaf2/libcloud/test/compute/fixtures/digitalocean_v1/list_locations.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/digitalocean_v1/list_locations.json b/libcloud/test/compute/fixtures/digitalocean_v1/list_locations.json
deleted file mode 100644
index a87b38f..0000000
--- a/libcloud/test/compute/fixtures/digitalocean_v1/list_locations.json
+++ /dev/null
@@ -1 +0,0 @@
-{"status":"OK","regions":[{"id":1,"name":"New York 1"},{"id":2,"name":"Amsterdam 1"}]}

http://git-wip-us.apache.org/repos/asf/libcloud/blob/f311aaf2/libcloud/test/compute/fixtures/digitalocean_v1/list_nodes.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/digitalocean_v1/list_nodes.json b/libcloud/test/compute/fixtures/digitalocean_v1/list_nodes.json
deleted file mode 100644
index 5fe5949..0000000
--- a/libcloud/test/compute/fixtures/digitalocean_v1/list_nodes.json
+++ /dev/null
@@ -1 +0,0 @@
-{"status":"OK","droplets":[{"id":119461,"name":"test-2","image_id":1601,"size_id":66,"region_id":1,"backups_active":null,"ip_address":null,"status":"new"}]}

http://git-wip-us.apache.org/repos/asf/libcloud/blob/f311aaf2/libcloud/test/compute/fixtures/digitalocean_v1/list_nodes_empty.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/digitalocean_v1/list_nodes_empty.json b/libcloud/test/compute/fixtures/digitalocean_v1/list_nodes_empty.json
deleted file mode 100644
index bc62108..0000000
--- a/libcloud/test/compute/fixtures/digitalocean_v1/list_nodes_empty.json
+++ /dev/null
@@ -1 +0,0 @@
-{"status":"OK","droplets":[]}

http://git-wip-us.apache.org/repos/asf/libcloud/blob/f311aaf2/libcloud/test/compute/fixtures/digitalocean_v1/list_nodes_page_2.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/digitalocean_v1/list_nodes_page_2.json b/libcloud/test/compute/fixtures/digitalocean_v1/list_nodes_page_2.json
deleted file mode 100644
index e6b89ba..0000000
--- a/libcloud/test/compute/fixtures/digitalocean_v1/list_nodes_page_2.json
+++ /dev/null
@@ -1,95 +0,0 @@
-{
-  "droplets": [
-    {
-      "id": 3164445,
-      "name": "example1.com",
-      "memory": 512,
-      "vcpus": 1,
-      "disk": 20,
-      "locked": false,
-      "status": "active",
-      "kernel": {
-        "id": 2233,
-        "name": "Ubuntu 14.04 x64 vmlinuz-3.13.0-37-generic",
-        "version": "3.13.0-37-generic"
-      },
-      "created_at": "2014-11-14T16:29:21Z",
-      "features": [
-        "backups",
-        "ipv6",
-        "virtio"
-      ],
-      "backup_ids": [
-        7938002
-      ],
-      "snapshot_ids": [
-
-      ],
-      "image": {
-        "id": 6918990,
-        "name": "14.04 x64",
-        "distribution": "Ubuntu",
-        "slug": "ubuntu-14-04-x64",
-        "public": true,
-        "regions": [
-          "nyc1",
-          "ams1",
-          "sfo1",
-          "nyc2",
-          "ams2",
-          "sgp1",
-          "lon1",
-          "nyc3",
-          "ams3",
-          "nyc3"
-        ],
-        "created_at": "2014-10-17T20:24:33Z",
-        "min_disk_size": 20
-      },
-      "size_slug": "512mb",
-      "networks": {
-        "v4": [
-          {
-            "ip_address": "104.236.32.182",
-            "netmask": "255.255.192.0",
-            "gateway": "104.236.0.1",
-            "type": "public"
-          }
-        ],
-        "v6": [
-          {
-            "ip_address": "2604:A880:0800:0010:0000:0000:02DD:4001",
-            "netmask": 64,
-            "gateway": "2604:A880:0800:0010:0000:0000:0000:0001",
-            "type": "public"
-          }
-        ]
-      },
-      "region": {
-        "name": "New York 3",
-        "slug": "nyc3",
-        "sizes": [
-
-        ],
-        "features": [
-          "virtio",
-          "private_networking",
-          "backups",
-          "ipv6",
-          "metadata"
-        ],
-        "available": null
-      }
-    }
-  ],
-  "links": {
-    "pages":
-      {
-        "first":"https://api.digitalocean.com/v2/droplets?page=1",
-        "prev":"https://api.digitalocean.com/v2/droplets?page=1"
-      }
-  },
-  "meta": {
-    "total":2
-  }
-}

http://git-wip-us.apache.org/repos/asf/libcloud/blob/f311aaf2/libcloud/test/compute/fixtures/digitalocean_v1/list_sizes.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/digitalocean_v1/list_sizes.json b/libcloud/test/compute/fixtures/digitalocean_v1/list_sizes.json
deleted file mode 100644
index 99acc57..0000000
--- a/libcloud/test/compute/fixtures/digitalocean_v1/list_sizes.json
+++ /dev/null
@@ -1 +0,0 @@
-{"status":"OK","sizes":[{"id":66,"name":"512MB"},{"id":63,"name":"1GB"},{"id":62,"name":"2GB"},{"id":64,"name":"4GB"},{"id":65,"name":"8GB"},{"id":61,"name":"16GB"},{"id":60,"name":"32GB"},{"id":70,"name":"48GB"},{"id":69,"name":"64GB"},{"id":68,"name":"96GB"}]}

http://git-wip-us.apache.org/repos/asf/libcloud/blob/f311aaf2/libcloud/test/compute/fixtures/digitalocean_v1/reboot_node.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/digitalocean_v1/reboot_node.json b/libcloud/test/compute/fixtures/digitalocean_v1/reboot_node.json
deleted file mode 100644
index bae818d..0000000
--- a/libcloud/test/compute/fixtures/digitalocean_v1/reboot_node.json
+++ /dev/null
@@ -1 +0,0 @@
-{"status":"OK","event_id":918910}

http://git-wip-us.apache.org/repos/asf/libcloud/blob/f311aaf2/libcloud/test/compute/test_digitalocean_v1.py
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/test_digitalocean_v1.py b/libcloud/test/compute/test_digitalocean_v1.py
deleted file mode 100644
index a09b1a8..0000000
--- a/libcloud/test/compute/test_digitalocean_v1.py
+++ /dev/null
@@ -1,206 +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.
-import sys
-import unittest
-
-try:
-    import simplejson as json
-except ImportError:
-    import json  # NOQA
-
-from libcloud.utils.py3 import httplib
-
-from libcloud.common.types import InvalidCredsError
-from libcloud.compute.base import NodeImage
-from libcloud.compute.drivers.digitalocean import DigitalOceanNodeDriver
-
-from libcloud.test import LibcloudTestCase, MockHttpTestCase
-from libcloud.test.file_fixtures import ComputeFileFixtures
-from libcloud.test.secrets import DIGITALOCEAN_v1_PARAMS
-from libcloud.test.secrets import DIGITALOCEAN_v2_PARAMS
-
-
-# class DigitalOceanTests(unittest.TestCase, TestCaseMixin):
-class DigitalOcean_v1_Tests(LibcloudTestCase):
-
-    def setUp(self):
-        DigitalOceanNodeDriver.connectionCls.conn_classes = \
-            (None, DigitalOceanMockHttp)
-        DigitalOceanMockHttp.type = None
-        self.driver = DigitalOceanNodeDriver(*DIGITALOCEAN_v1_PARAMS,
-                                             api_version='v1')
-
-    def test_v1_uses_v2_key(self):
-        self.assertRaises(InvalidCredsError, DigitalOceanNodeDriver,
-                          *DIGITALOCEAN_v2_PARAMS, api_version='v1')
-
-    def test_authentication(self):
-        DigitalOceanMockHttp.type = 'UNAUTHORIZED_CLIENT'
-        self.assertRaises(InvalidCredsError, self.driver.list_nodes)
-
-    def test_list_images_success(self):
-        images = self.driver.list_images()
-        self.assertTrue(len(images) >= 1)
-
-        image = images[0]
-        self.assertTrue(image.id is not None)
-        self.assertTrue(image.name is not None)
-
-    def test_list_sizes_success(self):
-        sizes = self.driver.list_sizes()
-        self.assertTrue(len(sizes) >= 1)
-
-        size = sizes[0]
-        self.assertTrue(size.id is not None)
-        self.assertEqual(size.name, '512MB')
-        self.assertEqual(size.ram, 512)
-
-        size = sizes[4]
-        self.assertTrue(size.id is not None)
-        self.assertEqual(size.name, '8GB')
-        self.assertEqual(size.ram, 8 * 1024)
-
-    def test_list_locations_success(self):
-        locations = self.driver.list_locations()
-        self.assertTrue(len(locations) >= 1)
-
-        location = locations[0]
-        self.assertEqual(location.id, '1')
-        self.assertEqual(location.name, 'New York 1')
-
-    def test_list_nodes_success(self):
-        nodes = self.driver.list_nodes()
-        self.assertEqual(len(nodes), 1)
-        self.assertEqual(nodes[0].name, 'test-2')
-        self.assertEqual(nodes[0].public_ips, [])
-        self.assertEqual(nodes[0].extra['image_id'], 1601)
-        self.assertEqual(nodes[0].extra['size_id'], 66)
-
-    def test_list_nodes_does_not_support_created_datetime(self):
-        nodes = self.driver.list_nodes()
-        self.assertIsNone(nodes[0].created_at)
-
-    def test_create_node_invalid_size(self):
-        image = NodeImage(id='invalid', name=None, driver=self.driver)
-        size = self.driver.list_sizes()[0]
-        location = self.driver.list_locations()[0]
-
-        DigitalOceanMockHttp.type = 'INVALID_IMAGE'
-        expected_msg = \
-            r'You specified an invalid image for Droplet creation. \(code: (404|HTTPStatus.NOT_FOUND)\)'
-        self.assertRaisesRegexp(Exception, expected_msg,
-                                self.driver.create_node,
-                                name='test', size=size, image=image,
-                                location=location)
-
-    def test_reboot_node_success(self):
-        node = self.driver.list_nodes()[0]
-        result = self.driver.reboot_node(node)
-        self.assertTrue(result)
-
-    def test_destroy_node_success(self):
-        node = self.driver.list_nodes()[0]
-        result = self.driver.destroy_node(node)
-        self.assertTrue(result)
-
-    def test_ex_rename_node_success(self):
-        node = self.driver.list_nodes()[0]
-        result = self.driver.ex_rename_node(node, 'fedora helios')
-        self.assertTrue(result)
-
-    def test_list_key_pairs(self):
-        keys = self.driver.list_key_pairs()
-        self.assertEqual(len(keys), 1)
-
-        self.assertEqual(keys[0].extra['id'], 7717)
-        self.assertEqual(keys[0].name, 'test1')
-        self.assertEqual(keys[0].public_key, None)
-
-    def test_ex_list_ssh_keys(self):
-        keys = self.driver.ex_list_ssh_keys()
-        self.assertEqual(len(keys), 1)
-
-        self.assertEqual(keys[0].id, 7717)
-        self.assertEqual(keys[0].name, 'test1')
-        self.assertEqual(keys[0].pub_key, None)
-
-    def test_delete_key_pair(self):
-        key = self.driver.list_key_pairs()[0]
-        result = self.driver.delete_key_pair(key)
-        self.assertTrue(result)
-
-    def test_ex_destroy_ssh_key(self):
-        key = self.driver.ex_list_ssh_keys()[0]
-        result = self.driver.ex_destroy_ssh_key(key.id)
-        self.assertTrue(result)
-
-
-class DigitalOceanMockHttp(MockHttpTestCase):
-    fixtures = ComputeFileFixtures('digitalocean_v1')
-
-    def _v1_regions(self, method, url, body, headers):
-        body = self.fixtures.load('list_locations.json')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _v1_images(self, method, url, body, headers):
-        body = self.fixtures.load('list_images.json')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _v1_sizes(self, method, url, body, headers):
-        body = self.fixtures.load('list_sizes.json')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _v1_droplets(self, method, url, body, headers):
-        body = self.fixtures.load('list_nodes.json')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _v1_droplets_new_INVALID_IMAGE(self, method, url, body, headers):
-        # reboot_node
-        body = self.fixtures.load('error_invalid_image.json')
-        return (httplib.NOT_FOUND, body, {},
-                httplib.responses[httplib.NOT_FOUND])
-
-    def _v1_droplets_119461_reboot(self, method, url, body, headers):
-        # reboot_node
-        body = self.fixtures.load('reboot_node.json')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _v1_droplets_119461_destroy(self, method, url, body, headers):
-        # destroy_node
-        self.assertUrlContainsQueryParams(url, {'scrub_data': '1'})
-        body = self.fixtures.load('destroy_node.json')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _v1_droplets_119461_rename(self, method, url, body, headers):
-        # reboot_node
-        self.assertUrlContainsQueryParams(url, {'name': 'fedora helios'})
-        body = self.fixtures.load('ex_rename_node.json')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _v1_ssh_keys(self, method, url, body, headers):
-        body = self.fixtures.load('ex_list_ssh_keys.json')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _v1_ssh_keys_7717_destroy(self, method, url, body, headers):
-        # destroy_ssh_key
-        body = self.fixtures.load('ex_destroy_ssh_key.json')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _v1_droplets_UNAUTHORIZED_CLIENT(self, method, url, body, headers):
-        body = self.fixtures.load('error.txt')
-        return (httplib.FOUND, body, {}, httplib.responses[httplib.FOUND])
-
-if __name__ == '__main__':
-    sys.exit(unittest.main())

http://git-wip-us.apache.org/repos/asf/libcloud/blob/f311aaf2/libcloud/test/compute/test_digitalocean_v2.py
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/test_digitalocean_v2.py b/libcloud/test/compute/test_digitalocean_v2.py
index 25e6e76..a215e81 100644
--- a/libcloud/test/compute/test_digitalocean_v2.py
+++ b/libcloud/test/compute/test_digitalocean_v2.py
@@ -26,6 +26,7 @@ except ImportError:
 from libcloud.utils.py3 import httplib
 
 from libcloud.common.types import InvalidCredsError
+from libcloud.common.digitalocean import DigitalOcean_v1_Error
 from libcloud.compute.base import NodeImage
 from libcloud.compute.drivers.digitalocean import DigitalOceanNodeDriver
 
@@ -44,6 +45,10 @@ class DigitalOcean_v2_Tests(LibcloudTestCase):
         DigitalOceanMockHttp.type = None
         self.driver = DigitalOceanNodeDriver(*DIGITALOCEAN_v2_PARAMS)
 
+    def test_v1_Error(self):
+        self.assertRaises(DigitalOcean_v1_Error, DigitalOceanNodeDriver,
+                          *DIGITALOCEAN_v1_PARAMS, api_version='v1')
+
     def test_v2_uses_v1_key(self):
         self.assertRaises(InvalidCredsError, DigitalOceanNodeDriver,
                           *DIGITALOCEAN_v1_PARAMS, api_version='v2')