From 298070ce9e2ea7ade053163751c30ff609a574ec Mon Sep 17 00:00:00 2001 From: Adam Wight Date: Fri, 26 Jan 2018 13:02:41 -0500 Subject: [PATCH] [LIBCLOUD-977] Adds rebuild and resize commands for DigitalOcean Implement the following DigitalOcean APIs as driver-specific extensions, * https://developers.digitalocean.com/documentation/v2/#rebuild-a-droplet * https://developers.digitalocean.com/documentation/v2/#resize-a-droplet --- libcloud/compute/drivers/digitalocean.py | 34 ++++++++++++++++++++++ .../fixtures/digitalocean_v2/ex_rebuild_node.json | 12 ++++++++ .../fixtures/digitalocean_v2/ex_resize_node.json | 12 ++++++++ libcloud/test/compute/test_digitalocean_v2.py | 25 ++++++++++++++++ 4 files changed, 83 insertions(+) create mode 100644 libcloud/test/compute/fixtures/digitalocean_v2/ex_rebuild_node.json create mode 100644 libcloud/test/compute/fixtures/digitalocean_v2/ex_resize_node.json diff --git a/libcloud/compute/drivers/digitalocean.py b/libcloud/compute/drivers/digitalocean.py index c8acdf04..58159556 100644 --- a/libcloud/compute/drivers/digitalocean.py +++ b/libcloud/compute/drivers/digitalocean.py @@ -280,6 +280,40 @@ class DigitalOcean_v2_NodeDriver(DigitalOcean_v2_BaseDriver, data=json.dumps(attr), method='POST') return res.status == httplib.CREATED + def ex_rebuild_node(self, node): + """ + Destroy and rebuild the node using its base image. + + :param node: Node to rebuild + :type node: :class:`Node` + + :return True if the operation began successfully + :rtype ``bool`` + """ + attr = {'type': 'rebuild', 'image': node.extra['image']['id']} + res = self.connection.request('/v2/droplets/%s/actions' % (node.id), + data=json.dumps(attr), method='POST') + return res.status == httplib.CREATED + + def ex_resize_node(self, node, size): + """ + Resize the node to a different machine size. Note that some resize + operations are reversible, and others are irreversible. + + :param node: Node to rebuild + :type node: :class:`Node` + + :param size: New size for this machine + :type node: :class:`NodeSize` + + :return True if the operation began successfully + :rtype ``bool`` + """ + attr = {'type': 'resize', 'size': size.name} + res = self.connection.request('/v2/droplets/%s/actions' % (node.id), + data=json.dumps(attr), method='POST') + return res.status == httplib.CREATED + def create_key_pair(self, name, public_key=''): """ Create a new SSH key. diff --git a/libcloud/test/compute/fixtures/digitalocean_v2/ex_rebuild_node.json b/libcloud/test/compute/fixtures/digitalocean_v2/ex_rebuild_node.json new file mode 100644 index 00000000..154ddce3 --- /dev/null +++ b/libcloud/test/compute/fixtures/digitalocean_v2/ex_rebuild_node.json @@ -0,0 +1,12 @@ +{ + "action": { + "id": 36804758, + "status": "in-progress", + "type": "rebuild", + "started_at": "2014-11-14T16:31:19Z", + "completed_at": null, + "resource_id": 3164450, + "resource_type": "droplet", + "region_slug": "nyc3" + } +} diff --git a/libcloud/test/compute/fixtures/digitalocean_v2/ex_resize_node.json b/libcloud/test/compute/fixtures/digitalocean_v2/ex_resize_node.json new file mode 100644 index 00000000..94f5f0cd --- /dev/null +++ b/libcloud/test/compute/fixtures/digitalocean_v2/ex_resize_node.json @@ -0,0 +1,12 @@ +{ + "action": { + "id": 36804758, + "status": "in-progress", + "type": "resize", + "started_at": "2014-11-14T16:31:19Z", + "completed_at": null, + "resource_id": 3164450, + "resource_type": "droplet", + "region_slug": "nyc3" + } +} diff --git a/libcloud/test/compute/test_digitalocean_v2.py b/libcloud/test/compute/test_digitalocean_v2.py index c0065e7d..1b049f92 100644 --- a/libcloud/test/compute/test_digitalocean_v2.py +++ b/libcloud/test/compute/test_digitalocean_v2.py @@ -155,6 +155,19 @@ class DigitalOcean_v2_Tests(LibcloudTestCase): result = self.driver.ex_hard_reboot(node) self.assertTrue(result) + def test_ex_rebuild_node_success(self): + node = self.driver.list_nodes()[0] + DigitalOceanMockHttp.type = 'REBUILD' + result = self.driver.ex_rebuild_node(node) + self.assertTrue(result) + + def test_ex_resize_node_success(self): + node = self.driver.list_nodes()[0] + size = self.driver.list_sizes()[0] + DigitalOceanMockHttp.type = 'RESIZE' + result = self.driver.ex_resize_node(node, size) + self.assertTrue(result) + def test_destroy_node_success(self): node = self.driver.list_nodes()[0] DigitalOceanMockHttp.type = 'DESTROY' @@ -362,6 +375,18 @@ class DigitalOceanMockHttp(MockHttp): body = self.fixtures.load('ex_hard_reboot.json') return (httplib.CREATED, body, {}, httplib.responses[httplib.OK]) + def _v2_droplets_3164444_actions_REBUILD(self, method, url, + body, headers): + # ex_rebuild_node + body = self.fixtures.load('ex_rebuild_node.json') + return (httplib.CREATED, body, {}, httplib.responses[httplib.OK]) + + def _v2_droplets_3164444_actions_RESIZE(self, method, url, + body, headers): + # ex_resize_node + body = self.fixtures.load('ex_resize_node.json') + return (httplib.CREATED, body, {}, httplib.responses[httplib.OK]) + def _v2_account_keys(self, method, url, body, headers): body = self.fixtures.load('list_key_pairs.json') return (httplib.OK, body, {}, httplib.responses[httplib.OK]) -- 2.14.3 (Apple Git-98)