From 2512a28dc1f9a017b996c648ecd2551162ef1fc3 Mon Sep 17 00:00:00 2001 From: huangtianhua Date: Thu, 22 Dec 2016 10:31:29 +0800 Subject: [PATCH] Make _console() public Heat wants to use 'novaclient.v2.servers. ServerManager._console' method to simplify the implementation of retrieving server console. It's better to change the method to public for public use. The patch changes: 1. add public method named get_console_url() for class 'novaclient.v2.servers.Server' 2. rename _console() to get_console_url() for class 'novaclient.v2.servers.ServerManager' Change-Id: I3d1485468d1d0a79d4002981ebe05b6cdf2332e7 Closes-Bug: #1651677 --- novaclient/exceptions.py | 8 ++ novaclient/tests/unit/v2/test_servers.py | 101 ++++++++++++++--- novaclient/v2/servers.py | 106 +++++++++++++----- .../make-console-public-0c776bfda240cd9d.yaml | 7 ++ 4 files changed, 180 insertions(+), 42 deletions(-) create mode 100644 releasenotes/notes/make-console-public-0c776bfda240cd9d.yaml diff --git a/novaclient/exceptions.py b/novaclient/exceptions.py index d23df8ab2..707aa889e 100644 --- a/novaclient/exceptions.py +++ b/novaclient/exceptions.py @@ -24,6 +24,14 @@ class UnsupportedVersion(Exception): pass +class UnsupportedConsoleType(Exception): + """Indicates that the user is trying to use an unsupported + console type when retrieving console urls of servers. + """ + def __init__(self, console_type): + self.message = 'Unsupported console_type "%s"' % console_type + + class UnsupportedAttribute(AttributeError): """Indicates that the user is trying to transmit the argument to a method, which is not supported by selected version. diff --git a/novaclient/tests/unit/v2/test_servers.py b/novaclient/tests/unit/v2/test_servers.py index 1d8a36fe8..a309d558a 100644 --- a/novaclient/tests/unit/v2/test_servers.py +++ b/novaclient/tests/unit/v2/test_servers.py @@ -794,44 +794,59 @@ class ServersTest(utils.FixturedTestCase): def test_get_vnc_console(self): s = self.cs.servers.get(1234) - vc = s.get_vnc_console('fake') + vc = s.get_vnc_console('novnc') self.assert_request_id(vc, fakes.FAKE_REQUEST_ID_LIST) self.assert_called('POST', '/servers/1234/action') - vc = self.cs.servers.get_vnc_console(s, 'fake') + vc = self.cs.servers.get_vnc_console(s, 'novnc') self.assert_request_id(vc, fakes.FAKE_REQUEST_ID_LIST) self.assert_called('POST', '/servers/1234/action') def test_get_spice_console(self): s = self.cs.servers.get(1234) - sc = s.get_spice_console('fake') + sc = s.get_spice_console('spice-html5') self.assert_request_id(sc, fakes.FAKE_REQUEST_ID_LIST) self.assert_called('POST', '/servers/1234/action') - sc = self.cs.servers.get_spice_console(s, 'fake') + sc = self.cs.servers.get_spice_console(s, 'spice-html5') self.assert_request_id(sc, fakes.FAKE_REQUEST_ID_LIST) self.assert_called('POST', '/servers/1234/action') def test_get_serial_console(self): s = self.cs.servers.get(1234) - sc = s.get_serial_console('fake') + sc = s.get_serial_console('serial') self.assert_request_id(sc, fakes.FAKE_REQUEST_ID_LIST) self.assert_called('POST', '/servers/1234/action') - sc = self.cs.servers.get_serial_console(s, 'fake') + sc = self.cs.servers.get_serial_console(s, 'serial') self.assert_request_id(sc, fakes.FAKE_REQUEST_ID_LIST) self.assert_called('POST', '/servers/1234/action') def test_get_rdp_console(self): s = self.cs.servers.get(1234) - rc = s.get_rdp_console('fake') + rc = s.get_rdp_console('rdp-html5') self.assert_request_id(rc, fakes.FAKE_REQUEST_ID_LIST) self.assert_called('POST', '/servers/1234/action') - rc = self.cs.servers.get_rdp_console(s, 'fake') + rc = self.cs.servers.get_rdp_console(s, 'rdp-html5') self.assert_request_id(rc, fakes.FAKE_REQUEST_ID_LIST) self.assert_called('POST', '/servers/1234/action') + def test_get_console_url(self): + s = self.cs.servers.get(1234) + rc = s.get_console_url('novnc') + self.assert_request_id(rc, fakes.FAKE_REQUEST_ID_LIST) + self.assert_called('POST', '/servers/1234/action') + + rc = self.cs.servers.get_console_url(s, 'novnc') + self.assert_request_id(rc, fakes.FAKE_REQUEST_ID_LIST) + self.assert_called('POST', '/servers/1234/action') + + # test the case with invalid console type + self.assertRaises(exceptions.UnsupportedConsoleType, + s.get_console_url, + 'invalid') + def test_create_image(self): s = self.cs.servers.get(1234) im = s.create_image('123') @@ -1001,44 +1016,83 @@ class ServersV26Test(ServersTest): def test_get_vnc_console(self): s = self.cs.servers.get(1234) - vc = s.get_vnc_console('fake') + vc = s.get_vnc_console('novnc') self.assert_request_id(vc, fakes.FAKE_REQUEST_ID_LIST) self.assert_called('POST', '/servers/1234/remote-consoles') - vc = self.cs.servers.get_vnc_console(s, 'fake') + vc = self.cs.servers.get_vnc_console(s, 'novnc') self.assert_request_id(vc, fakes.FAKE_REQUEST_ID_LIST) self.assert_called('POST', '/servers/1234/remote-consoles') + # test the case with invalid console type + self.assertRaises(exceptions.UnsupportedConsoleType, + s.get_vnc_console, + 'invalid') + def test_get_spice_console(self): s = self.cs.servers.get(1234) - sc = s.get_spice_console('fake') + sc = s.get_spice_console('spice-html5') self.assert_request_id(sc, fakes.FAKE_REQUEST_ID_LIST) self.assert_called('POST', '/servers/1234/remote-consoles') - sc = self.cs.servers.get_spice_console(s, 'fake') + sc = self.cs.servers.get_spice_console(s, 'spice-html5') self.assert_request_id(sc, fakes.FAKE_REQUEST_ID_LIST) self.assert_called('POST', '/servers/1234/remote-consoles') + # test the case with invalid console type + self.assertRaises(exceptions.UnsupportedConsoleType, + s.get_spice_console, + 'invalid') + def test_get_serial_console(self): s = self.cs.servers.get(1234) - sc = s.get_serial_console('fake') + sc = s.get_serial_console('serial') self.assert_request_id(sc, fakes.FAKE_REQUEST_ID_LIST) self.assert_called('POST', '/servers/1234/remote-consoles') - sc = self.cs.servers.get_serial_console(s, 'fake') + sc = self.cs.servers.get_serial_console(s, 'serial') self.assert_request_id(sc, fakes.FAKE_REQUEST_ID_LIST) self.assert_called('POST', '/servers/1234/remote-consoles') + # test the case with invalid console type + self.assertRaises(exceptions.UnsupportedConsoleType, + s.get_serial_console, + 'invalid') + def test_get_rdp_console(self): s = self.cs.servers.get(1234) - rc = s.get_rdp_console('fake') + rc = s.get_rdp_console('rdp-html5') self.assert_request_id(rc, fakes.FAKE_REQUEST_ID_LIST) self.assert_called('POST', '/servers/1234/remote-consoles') - rc = self.cs.servers.get_rdp_console(s, 'fake') + rc = self.cs.servers.get_rdp_console(s, 'rdp-html5') self.assert_request_id(rc, fakes.FAKE_REQUEST_ID_LIST) self.assert_called('POST', '/servers/1234/remote-consoles') + # test the case with invalid console type + self.assertRaises(exceptions.UnsupportedConsoleType, + s.get_rdp_console, + 'invalid') + + def test_get_console_url(self): + s = self.cs.servers.get(1234) + vc = s.get_console_url('novnc') + self.assert_request_id(vc, fakes.FAKE_REQUEST_ID_LIST) + self.assert_called('POST', '/servers/1234/remote-consoles') + + vc = self.cs.servers.get_console_url(s, 'novnc') + self.assert_request_id(vc, fakes.FAKE_REQUEST_ID_LIST) + self.assert_called('POST', '/servers/1234/remote-consoles') + + # test the case with invalid console type + self.assertRaises(exceptions.UnsupportedConsoleType, + s.get_console_url, + 'invalid') + # console type webmks is supported since api version 2.8 + self.assertRaises(exceptions.UnsupportedConsoleType, + s.get_console_url, + 'webmks') + class ServersV28Test(ServersV26Test): @@ -1054,6 +1108,21 @@ class ServersV28Test(ServersV26Test): self.assert_request_id(mksc, fakes.FAKE_REQUEST_ID_LIST) self.assert_called('POST', '/servers/1234/remote-consoles') + def test_get_console_url(self): + s = self.cs.servers.get(1234) + mksc = s.get_console_url('novnc') + self.assert_request_id(mksc, fakes.FAKE_REQUEST_ID_LIST) + self.assert_called('POST', '/servers/1234/remote-consoles') + + mksc = self.cs.servers.get_console_url(s, 'novnc') + self.assert_request_id(mksc, fakes.FAKE_REQUEST_ID_LIST) + self.assert_called('POST', '/servers/1234/remote-consoles') + + # test the case with invalid console type + self.assertRaises(exceptions.UnsupportedConsoleType, + s.get_console_url, + 'invalid') + class ServersV214Test(ServersV28Test): diff --git a/novaclient/v2/servers.py b/novaclient/v2/servers.py index ee828fdcf..460355630 100644 --- a/novaclient/v2/servers.py +++ b/novaclient/v2/servers.py @@ -35,6 +35,23 @@ from novaclient.v2 import security_groups REBOOT_SOFT, REBOOT_HARD = 'SOFT', 'HARD' +CONSOLE_TYPE_ACTION_MAPPING = { + 'novnc': 'os-getVNCConsole', + 'xvpvnc': 'os-getVNCConsole', + 'spice-html5': 'os-getSPICEConsole', + 'rdp-html5': 'os-getRDPConsole', + 'serial': 'os-getSerialConsole' +} + +CONSOLE_TYPE_PROTOCOL_MAPPING = { + 'novnc': 'vnc', + 'xvpvnc': 'vnc', + 'spice-html5': 'spice', + 'rdp-html5': 'rdp', + 'serial': 'serial', + 'webmks': 'mks' +} + class Server(base.Resource): HUMAN_ID = True @@ -121,6 +138,15 @@ class Server(base.Resource): """ return self.manager.get_mks_console(self) + def get_console_url(self, console_type): + """ + Retrieve a console of a particular protocol and console_type + + :param console_type: Type of console + """ + + return self.manager.get_console_url(self, console_type) + def get_password(self, private_key=None): """ Get password for a Server. @@ -904,7 +930,7 @@ class ServerManager(base.BootingManagerWithFind): :returns: An instance of novaclient.base.DictWithMeta """ - return self._action('os-getVNCConsole', server, {'type': console_type}) + return self.get_console_url(server, console_type) @api_versions.wraps('2.0', '2.5') def get_spice_console(self, server, console_type): @@ -916,8 +942,7 @@ class ServerManager(base.BootingManagerWithFind): :returns: An instance of novaclient.base.DictWithMeta """ - return self._action('os-getSPICEConsole', server, - {'type': console_type}) + return self.get_console_url(server, console_type) @api_versions.wraps('2.0', '2.5') def get_rdp_console(self, server, console_type): @@ -929,8 +954,7 @@ class ServerManager(base.BootingManagerWithFind): :returns: An instance of novaclient.base.DictWithMeta """ - return self._action('os-getRDPConsole', server, - {'type': console_type}) + return self.get_console_url(server, console_type) @api_versions.wraps('2.0', '2.5') def get_serial_console(self, server, console_type): @@ -942,8 +966,29 @@ class ServerManager(base.BootingManagerWithFind): :returns: An instance of novaclient.base.DictWithMeta """ - return self._action('os-getSerialConsole', server, - {'type': console_type}) + return self.get_console_url(server, console_type) + + def _get_protocol(self, console_type): + protocol = CONSOLE_TYPE_PROTOCOL_MAPPING.get(console_type) + if not protocol: + raise exceptions.UnsupportedConsoleType(console_type) + + return protocol + + @api_versions.wraps('2.0', '2.5') + def get_console_url(self, server, console_type): + """ + Retrieve a console url of a server. + + :param server: server to get console url for + :param console_type: type can be novnc, xvpvnc, spice-html5, + rdp-html5 and serial. + """ + + action = CONSOLE_TYPE_ACTION_MAPPING.get(console_type) + if not action: + raise exceptions.UnsupportedConsoleType(console_type) + return self._action(action, server, {'type': console_type}) @api_versions.wraps('2.6') def get_vnc_console(self, server, console_type): @@ -955,8 +1000,7 @@ class ServerManager(base.BootingManagerWithFind): :returns: An instance of novaclient.base.DictWithMeta """ - return self._console(server, - {'protocol': 'vnc', 'type': console_type}) + return self.get_console_url(server, console_type) @api_versions.wraps('2.6') def get_spice_console(self, server, console_type): @@ -968,8 +1012,7 @@ class ServerManager(base.BootingManagerWithFind): :returns: An instance of novaclient.base.DictWithMeta """ - return self._console(server, - {'protocol': 'spice', 'type': console_type}) + return self.get_console_url(server, console_type) @api_versions.wraps('2.6') def get_rdp_console(self, server, console_type): @@ -981,8 +1024,7 @@ class ServerManager(base.BootingManagerWithFind): :returns: An instance of novaclient.base.DictWithMeta """ - return self._console(server, - {'protocol': 'rdp', 'type': console_type}) + return self.get_console_url(server, console_type) @api_versions.wraps('2.6') def get_serial_console(self, server, console_type): @@ -994,8 +1036,7 @@ class ServerManager(base.BootingManagerWithFind): :returns: An instance of novaclient.base.DictWithMeta """ - return self._console(server, - {'protocol': 'serial', 'type': console_type}) + return self.get_console_url(server, console_type) @api_versions.wraps('2.8') def get_mks_console(self, server): @@ -1006,8 +1047,30 @@ class ServerManager(base.BootingManagerWithFind): :returns: An instance of novaclient.base.DictWithMeta """ - return self._console(server, - {'protocol': 'mks', 'type': 'webmks'}) + return self.get_console_url(server, 'webmks') + + @api_versions.wraps('2.6') + def get_console_url(self, server, console_type): + """ + Retrieve a console url of a server. + + :param server: server to get console url for + :param console_type: type can be novnc/xvpvnc for protocol vnc; + spice-html5 for protocol spice; rdp-html5 for + protocol rdp; serial for protocol serial. + webmks for protocol mks (since version 2.8). + """ + + if self.api_version < api_versions.APIVersion('2.8'): + if console_type == 'webmks': + raise exceptions.UnsupportedConsoleType(console_type) + + protocol = self._get_protocol(console_type) + body = {'remote_console': {'protocol': protocol, + 'type': console_type}} + url = '/servers/%s/remote-consoles' % base.getid(server) + resp, body = self.api.client.post(url, body=body) + return self.convert_into_with_meta(body, resp) def get_password(self, server, private_key=None): """ @@ -1855,15 +1918,6 @@ class ServerManager(base.BootingManagerWithFind): url = '/servers/%s/action' % base.getid(server) return self.api.client.post(url, body=body) - def _console(self, server, info=None, **kwargs): - """ - Retrieve a console of a particular protocol -- vnc/spice/rdp/serial - """ - body = {'remote_console': info} - url = '/servers/%s/remote-consoles' % base.getid(server) - resp, body = self.api.client.post(url, body=body) - return self.convert_into_with_meta(body, resp) - @api_versions.wraps('2.26') def tag_list(self, server): """ diff --git a/releasenotes/notes/make-console-public-0c776bfda240cd9d.yaml b/releasenotes/notes/make-console-public-0c776bfda240cd9d.yaml new file mode 100644 index 000000000..e8743f67a --- /dev/null +++ b/releasenotes/notes/make-console-public-0c776bfda240cd9d.yaml @@ -0,0 +1,7 @@ +--- +features: + - Provides a public unified interface 'get_console_url' for classes + 'novaclient.v2.servers.Server' and 'novaclient.v2.servers.ServerManager'. + Users (Heat, OpenStack-client and etc.) can call this public interface + instead of calling the individual methods to retrieve a console url + of a particular protocol.