diff --git libcloud/compute/drivers/openstack.py libcloud/compute/drivers/openstack.py index 3dfeb2b..b9a5ffe 100644 --- libcloud/compute/drivers/openstack.py +++ libcloud/compute/drivers/openstack.py @@ -1099,3 +1099,17 @@ class OpenStack_1_1_NodeDriver(OpenStackNodeDriver): path = urlparse.urlparse(location_header).path image_id = path.split('/')[-1] return image_id + + def ex_rescue(self, node, password=None): + # Requires Rescue Mode extension + if password: + resp = self._node_action(node, 'rescue', adminPass=password) + else: + resp = self._node_action(node, 'rescue') + password = json.loads(resp.body)['adminPass'] + node.extra['password'] = password + return node + + def ex_unrescue(self, node): + resp = self._node_action(node, 'unrescue') + return resp.status == httplib.ACCEPTED diff --git test/compute/test_openstack.py test/compute/test_openstack.py index e377603..800f1fa 100644 --- test/compute/test_openstack.py +++ test/compute/test_openstack.py @@ -840,6 +840,24 @@ class OpenStack_1_1_Tests(unittest.TestCase, TestCaseMixin): params = [("key", "value1"), ("key", "value2") ] self.driver.connection.request("/servers/12067", params=params) + def test_ex_rescue_with_password(self): + node = Node(id=12064, name=None, state=None, public_ips=None, + private_ips=None, driver=self.driver) + n = self.driver.ex_rescue(node, 'foo') + self.assertEqual(n.extra['password'], 'foo') + + def test_ex_rescue_no_password(self): + node = Node(id=12064, name=None, state=None, public_ips=None, + private_ips=None, driver=self.driver) + n = self.driver.ex_rescue(node) + self.assertEqual(n.extra['password'], 'foo') + + def test_ex_unrescue(self): + node = Node(id=12064, name=None, state=None, public_ips=None, + private_ips=None, driver=self.driver) + result = self.driver.ex_unrescue(node) + self.assertTrue(result) + class OpenStack_1_1_FactoryMethodTests(OpenStack_1_1_Tests): should_list_locations = False @@ -909,6 +927,9 @@ class OpenStack_1_1_MockHttp(MockHttpTestCase): return (httplib.ACCEPTED, "", {"location": "http://127.0.0.1/v1.1/68/images/4949f9ee-2421-4c81-8b49-13119446008b"}, httplib.responses[httplib.ACCEPTED]) + elif "rescue" in json.loads(body): + return (httplib.OK, '{"adminPass": "foo"}', {}, + httplib.responses[httplib.OK]) return (httplib.ACCEPTED, "", {}, httplib.responses[httplib.ACCEPTED])