From fa5b9ffdc2310393ec01d0731c7dd37819c2c610 Mon Sep 17 00:00:00 2001 From: Terry Howe Date: Fri, 8 Aug 2014 21:13:22 -0600 Subject: [PATCH] Various standard server actions Change-Id: I53d32018cc50b35a005434f816e0475312bc808b --- openstack/compute/v2/server.py | 60 ++++++++++ openstack/tests/compute/v2/test_server.py | 135 ++++++++++++++++++++++ 2 files changed, 195 insertions(+) diff --git a/openstack/compute/v2/server.py b/openstack/compute/v2/server.py index 5a93b4103..69480c480 100644 --- a/openstack/compute/v2/server.py +++ b/openstack/compute/v2/server.py @@ -12,6 +12,7 @@ from openstack.compute import compute_service from openstack import resource +from openstack import utils class Server(resource.Resource): @@ -43,3 +44,62 @@ class Server(resource.Resource): status = resource.prop('status') updated = resource.prop('updated') user_id = resource.prop('user_id') + + def action(self, session, body): + """Preform server actions given the message body.""" + url = utils.urljoin(self.base_path, self.id, 'action') + resp = session.put(url, service=self.service, json=body).body + return resp + + def change_password(self, session, new_password): + """Change the administrator password to the given password.""" + body = {'changePassword': {'adminPass': new_password}} + return self.action(session, body) + + def reboot(self, session, reboot_type): + """Reboot server where reboot_type might be 'SOFT' or 'HARD'.""" + body = {'reboot': {'type': reboot_type}} + return self.action(session, body) + + def rebuild(self, session, name, image_href, admin_password, + access_ipv4=None, access_ipv6=None, + metadata=None, personality=None): + """Rebuild the server with the given arguments.""" + action = { + 'name': name, + 'adminPass': admin_password, + 'imageRef': image_href, + } + if access_ipv4 is not None: + action['accessIPv4'] = access_ipv4 + if access_ipv6 is not None: + action['accessIPv6'] = access_ipv6 + if metadata is not None: + action['metadata'] = metadata + if personality is not None: + action['personality'] = personality + body = {'rebuild': action} + return self.action(session, body) + + def resize(self, session, flavor): + """Resize server to flavor reference.""" + body = {'resize': {'flavorRef': flavor}} + return self.action(session, body) + + def confirm_resize(self, session): + """Confirm the resize of the server.""" + body = {'confirmResize': None} + return self.action(session, body) + + def revert_resize(self, session): + """Revert the resize of the server.""" + body = {'revertResize': None} + return self.action(session, body) + + def create_image(self, session, name, metadata=None): + """Create image from server.""" + action = {'name': name} + if metadata is not None: + action['metadata'] = metadata + body = {'createImage': action} + return self.action(session, body) diff --git a/openstack/tests/compute/v2/test_server.py b/openstack/tests/compute/v2/test_server.py index 229d25a1a..faf46c27c 100644 --- a/openstack/tests/compute/v2/test_server.py +++ b/openstack/tests/compute/v2/test_server.py @@ -10,6 +10,7 @@ # License for the specific language governing permissions and limitations # under the License. +import mock import testtools from openstack.compute.v2 import server @@ -37,6 +38,14 @@ EXAMPLE = { class TestServer(testtools.TestCase): + def setUp(self): + super(TestServer, self).setUp() + self.resp = mock.Mock() + self.resp.body = '' + self.sess = mock.Mock() + self.sess.put = mock.MagicMock() + self.sess.put.return_value = self.resp + def test_basic(self): sot = server.Server() self.assertEqual('server', sot.resource_key) @@ -67,3 +76,129 @@ class TestServer(testtools.TestCase): self.assertEqual(EXAMPLE['status'], sot.status) self.assertEqual(EXAMPLE['updated'], sot.updated) self.assertEqual(EXAMPLE['user_id'], sot.user_id) + + def test_change_passowrd(self): + sot = server.Server(EXAMPLE) + + self.assertEqual(self.resp.body, sot.change_password(self.sess, 'a')) + + url = 'servers/IDENTIFIER/action' + body = {"changePassword": {"adminPass": "a"}} + self.sess.put.assert_called_with(url, service=sot.service, json=body) + + def test_reboot(self): + sot = server.Server(EXAMPLE) + + self.assertEqual(self.resp.body, sot.reboot(self.sess, 'HARD')) + + url = 'servers/IDENTIFIER/action' + body = {"reboot": {"type": "HARD"}} + self.sess.put.assert_called_with(url, service=sot.service, json=body) + + def test_rebuild(self): + sot = server.Server(EXAMPLE) + + self.assertEqual( + self.resp.body, + sot.rebuild( + self.sess, + name='noo', + image_href='http://image/1', + admin_password='seekr3t', + access_ipv4="12.34.56.78", + access_ipv6="fe80::100", + metadata={"meta var": "meta val"}, + personality=[{"path": "/etc/motd", "contents": "foo"}], + ) + ) + + url = 'servers/IDENTIFIER/action' + body = { + "rebuild": { + "name": "noo", + "imageRef": "http://image/1", + "adminPass": "seekr3t", + "accessIPv4": "12.34.56.78", + "accessIPv6": "fe80::100", + "metadata": {"meta var": "meta val"}, + "personality": [{"path": "/etc/motd", "contents": "foo"}], + } + } + self.sess.put.assert_called_with(url, service=sot.service, json=body) + + def test_rebuild_minimal(self): + sot = server.Server(EXAMPLE) + + self.assertEqual( + self.resp.body, + sot.rebuild( + self.sess, + name='nootoo', + image_href='http://image/2', + admin_password='seekr3two', + ) + ) + + url = 'servers/IDENTIFIER/action' + body = { + "rebuild": { + "name": "nootoo", + "imageRef": "http://image/2", + "adminPass": "seekr3two", + } + } + self.sess.put.assert_called_with(url, service=sot.service, json=body) + + def test_resize(self): + sot = server.Server(EXAMPLE) + + self.assertEqual(self.resp.body, sot.resize(self.sess, '2')) + + url = 'servers/IDENTIFIER/action' + body = {"resize": {"flavorRef": "2"}} + self.sess.put.assert_called_with(url, service=sot.service, json=body) + + def test_confirm_resize(self): + sot = server.Server(EXAMPLE) + + self.assertEqual(self.resp.body, sot.confirm_resize(self.sess)) + + url = 'servers/IDENTIFIER/action' + body = {"confirmResize": None} + self.sess.put.assert_called_with(url, service=sot.service, json=body) + + def test_revert_resize(self): + sot = server.Server(EXAMPLE) + + self.assertEqual(self.resp.body, sot.revert_resize(self.sess)) + + url = 'servers/IDENTIFIER/action' + body = {"revertResize": None} + self.sess.put.assert_called_with(url, service=sot.service, json=body) + + def test_create_image(self): + sot = server.Server(EXAMPLE) + name = 'noo' + metadata = {'nu': 'image', 'created': 'today'} + + self.assertEqual( + self.resp.body, + sot.create_image(self.sess, name, metadata) + ) + + url = 'servers/IDENTIFIER/action' + body = {"createImage": {'name': name, 'metadata': metadata}} + self.sess.put.assert_called_with(url, service=sot.service, json=body) + + def test_create_image_minimal(self): + sot = server.Server(EXAMPLE) + name = 'noo' + + self.assertEqual( + self.resp.body, + sot.create_image(self.sess, name) + ) + + url = 'servers/IDENTIFIER/action' + body = {"createImage": {'name': name}} + self.sess.put.assert_called_with(url, service=sot.service, json=body)