Repository: libcloud Updated Branches: refs/heads/trunk e2e17414d -> 1ac9467a9
add ex_get_node_details for digitalocean_v2 driver Adds ex_get_node_details for the digitalocean_v2 driver. This method already exists for other drivers like [OpenStack](https://github.com/apache/libcloud/blob/e2e17414dd9e8ba3542e181885ec242b820bfc48/libcloud/compute/drivers/openstack.py#L317). Right now to list one node object using the DigitalOcean driver you can run .list_nodes and then filter out the one you need by ID. This works fine, but once start using that on accounts with many instances (thousands) that will becomes slow and the chance of encountering API exceptions goes up and you end up with frequent errors like: ``` return connection.list_nodes() File "/usr/local/venv/project/src/apache-libcloud/libcloud/compute/drivers/digitalocean.py", line 349, in list_nodes data = self._paginated_request('/v2/droplets', 'droplets') File "/usr/local/venv/project/src/apache-libcloud/libcloud/common/digitalocean.py", line 242, in _paginated_request new_data = self.connection.request(url, params=params) File "/usr/local/venv/project/src/apache-libcloud/libcloud/common/base.py", line 862, in request response = responseCls(**kwargs) File "/usr/local/venv/project/src/apache-libcloud/libcloud/common/base.py", line 179, in __init__ headers=self.headers) BaseHTTPError: Server was unable to give you a response. (code: 500) ``` Or also very often: ``` MalformedResponseError: <MalformedResponseException in <project.provisioning.driver.digitalocean.DigitalOcean_v2_NodeDriver object at 0x4f1c290> 'Failed to parse JSON'>: '<!DOCTYPE html>\n<html>\n<head>\n <title>DigitalOcean - Something went wrong!</ ``` Using .ex_get_node_details instead of .list_nodes when you need to retrieve a node object by droplet ID will make that action faster and less likely to fail. Signed-off-by: Rick van de Loo <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/b07498d5 Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/b07498d5 Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/b07498d5 Branch: refs/heads/trunk Commit: b07498d5a7513ba798259cbeda16e91d65a14c51 Parents: e2e1741 Author: Rick van de Loo <[email protected]> Authored: Sun Jul 1 16:20:31 2018 +0200 Committer: Rick van de Loo <[email protected]> Committed: Sun Jul 1 19:04:37 2018 +0200 ---------------------------------------------------------------------- libcloud/compute/drivers/digitalocean.py | 14 +++ .../fixtures/digitalocean_v2/list_node.json | 112 +++++++++++++++++++ libcloud/test/compute/test_digitalocean_v2.py | 12 ++ 3 files changed, 138 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/libcloud/blob/b07498d5/libcloud/compute/drivers/digitalocean.py ---------------------------------------------------------------------- diff --git a/libcloud/compute/drivers/digitalocean.py b/libcloud/compute/drivers/digitalocean.py index f883763..631f8d9 100644 --- a/libcloud/compute/drivers/digitalocean.py +++ b/libcloud/compute/drivers/digitalocean.py @@ -495,6 +495,20 @@ class DigitalOcean_v2_NodeDriver(DigitalOcean_v2_BaseDriver, method='DELETE') return res.status == httplib.NO_CONTENT + 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` + """ + data = self._paginated_request( + '/v2/droplets/{}'.format(node_id), 'droplet' + ) + return self._to_node(data) + def ex_create_floating_ip(self, location): """ Create new floating IP reserved to a region. http://git-wip-us.apache.org/repos/asf/libcloud/blob/b07498d5/libcloud/test/compute/fixtures/digitalocean_v2/list_node.json ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/digitalocean_v2/list_node.json b/libcloud/test/compute/fixtures/digitalocean_v2/list_node.json new file mode 100644 index 0000000..33c571f --- /dev/null +++ b/libcloud/test/compute/fixtures/digitalocean_v2/list_node.json @@ -0,0 +1,112 @@ +{ + "droplet": { + "status": "active", + "kernel": { + "version": "3.13.0-57-generic", + "id": 5175, + "name": "Ubuntu 14.04 x64 vmlinuz-3.13.0-57-generic" + }, + "volume_ids": [], + "locked": false, + "name": "example.com", + "backup_ids": [], + "created_at": "2015-11-10T11:01:41Z", + "snapshot_ids": [], + "size_slug": "8gb", + "networks": { + "v4": [ + { + "type": "public", + "netmask": "255.255.255.0", + "ip_address": "36.123.0.123", + "gateway": "36.123.0.1" + } + ], + "v6": [] + }, + "next_backup_window": null, + "vcpus": 4, + "size": { + "price_monthly": 80.0, + "available": true, + "transfer": 5.0, + "price_hourly": 0.11905, + "regions": [ + "ams2", + "ams3", + "blr1", + "fra1", + "lon1", + "nyc1", + "nyc2", + "nyc3", + "sfo1", + "sfo2", + "sgp1", + "tor1" + ], + "vcpus": 4, + "memory": 8192, + "disk": 80, + "slug": "8gb" + }, + "image": { + "min_disk_size": 20, + "slug": null, + "name": "14.04 x64", + "created_at": "2014-13-13T20:20:20Z", + "id": 12089443, + "regions": [ + "ams2", + "nyc3" + ], + "distribution": "Ubuntu", + "type": "snapshot", + "public": false, + "size_gigabytes": 1.76 + }, + "memory": 8192, + "region": { + "available": true, + "sizes": [ + "32gb", + "16gb", + "2gb", + "1gb", + "4gb", + "8gb", + "512mb", + "48gb", + "s-1vcpu-3gb", + "m-1vcpu-8gb", + "m-16gb", + "m-32gb", + "s-1vcpu-1gb", + "s-1vcpu-2gb", + "s-2vcpu-2gb", + "s-3vcpu-1gb", + "s-2vcpu-4gb", + "s-4vcpu-8gb", + "s-6vcpu-16gb", + "s-8vcpu-32gb", + "s-12vcpu-48gb" + ], + "features": [ + "private_networking", + "backups", + "ipv6", + "metadata", + "install_agent", + "image_transfer" + ], + "name": "Amsterdam 2", + "slug": "ams2" + }, + "disk": 40, + "id": 3164444, + "tags": ["mytag1", "mytag2"], + "features": [ + "virtio" + ] + } +} http://git-wip-us.apache.org/repos/asf/libcloud/blob/b07498d5/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 775929d..84fff2c 100644 --- a/libcloud/test/compute/test_digitalocean_v2.py +++ b/libcloud/test/compute/test_digitalocean_v2.py @@ -292,6 +292,14 @@ class DigitalOcean_v2_Tests(LibcloudTestCase): result = self.driver.delete_volume_snapshot(snapshot) self.assertTrue(result) + def test_ex_get_node_details(self): + node = self.driver.ex_get_node_details('3164444') + self.assertEqual(node.name, 'example.com') + self.assertEqual(node.public_ips, ['36.123.0.123']) + self.assertEqual(node.extra['image']['id'], 12089443) + self.assertEqual(node.extra['size_slug'], '8gb') + self.assertEqual(len(node.extra['tags']), 2) + def test_ex_create_floating_ip(self): nyc1 = [r for r in self.driver.list_locations() if r.id == 'nyc1'][0] floating_ip = self.driver.ex_create_floating_ip(nyc1) @@ -377,6 +385,10 @@ class DigitalOceanMockHttp(MockHttp): body = self.fixtures.load('list_nodes.json') return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + def _v2_droplets_3164444(self, method, url, body, headers): + body = self.fixtures.load('list_node.json') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + def _v2_droplets_INVALID_IMAGE(self, method, url, body, headers): body = self.fixtures.load('error_invalid_image.json') return (httplib.NOT_FOUND, body, {},
