diff options
author | Jenkins <jenkins@review.openstack.org> | 2015-10-23 12:56:32 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2015-10-23 12:56:32 +0000 |
commit | a5363ae0d60d41feff23f6cca44fcd7aa9fc5b8b (patch) | |
tree | 86ee23171d47dd2e967baadc784d23cf9e0fe07c | |
parent | 5d5def785d0e9f39de8cfcda0fb720c9efe4f261 (diff) | |
parent | cce7cd32775bc9d77a5ad57971be5d7c36e3aee5 (diff) | |
download | python-novaclient-a5363ae0d60d41feff23f6cca44fcd7aa9fc5b8b.tar.gz |
Merge "Support the server side remote-console API changes"2.33.0
-rw-r--r-- | novaclient/__init__.py | 2 | ||||
-rw-r--r-- | novaclient/tests/functional/v2/legacy/test_consoles.py | 67 | ||||
-rw-r--r-- | novaclient/tests/functional/v2/test_consoles.py | 32 | ||||
-rw-r--r-- | novaclient/tests/unit/fixture_data/servers.py | 18 | ||||
-rw-r--r-- | novaclient/tests/unit/v2/test_servers.py | 39 | ||||
-rw-r--r-- | novaclient/v2/servers.py | 61 | ||||
-rw-r--r-- | novaclient/v2/shell.py | 22 |
7 files changed, 236 insertions, 5 deletions
diff --git a/novaclient/__init__.py b/novaclient/__init__.py index 6018232b..00420237 100644 --- a/novaclient/__init__.py +++ b/novaclient/__init__.py @@ -25,4 +25,4 @@ API_MIN_VERSION = api_versions.APIVersion("2.1") # when client supported the max version, and bumped sequentially, otherwise # the client may break due to server side new version may include some # backward incompatible change. -API_MAX_VERSION = api_versions.APIVersion("2.5") +API_MAX_VERSION = api_versions.APIVersion("2.6") diff --git a/novaclient/tests/functional/v2/legacy/test_consoles.py b/novaclient/tests/functional/v2/legacy/test_consoles.py new file mode 100644 index 00000000..5ca022a7 --- /dev/null +++ b/novaclient/tests/functional/v2/legacy/test_consoles.py @@ -0,0 +1,67 @@ +# Copyright 2015 IBM Corp. +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from tempest_lib import exceptions + +from novaclient.tests.functional import base +from novaclient.v2 import shell + + +class TestConsolesNovaClient(base.ClientTestBase): + """Consoles functional tests.""" + + COMPUTE_API_VERSION = "2.1" + + def _create_server(self): + name = self.name_generate(prefix='server') + server = self.client.servers.create(name, self.image, self.flavor) + shell._poll_for_status( + self.client.servers.get, server.id, + 'building', ['active']) + self.addCleanup(server.delete) + return server + + def _test_console_get(self, command): + server = self._create_server() + completed_command = command % server.id + self.assertRaises(exceptions.CommandFailed, + self.nova, completed_command) + + try: + self.nova(completed_command) + except exceptions.CommandFailed as cf: + self.assertTrue('HTTP 400' in str(cf.stderr)) + + def _test_vnc_console_get(self): + self._test_console_get('get-vnc-console %s novnc') + + def _test_spice_console_get(self): + self._test_console_get('get-spice-console %s spice-html5') + + def _test_rdp_console_get(self): + self._test_console_get('get-rdp-console %s rdp-html5') + + def _test_serial_console_get(self): + self._test_console_get('get-serial-console %s') + + def test_vnc_console_get(self): + self._test_vnc_console_get() + + def test_spice_console_get(self): + self._test_spice_console_get() + + def test_rdp_console_get(self): + self._test_rdp_console_get() + + def test_serial_console_get(self): + self._test_serial_console_get() diff --git a/novaclient/tests/functional/v2/test_consoles.py b/novaclient/tests/functional/v2/test_consoles.py new file mode 100644 index 00000000..37615af7 --- /dev/null +++ b/novaclient/tests/functional/v2/test_consoles.py @@ -0,0 +1,32 @@ +# Copyright 2015 IBM Corp. +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from novaclient.tests.functional.v2.legacy import test_consoles + + +class TestConsolesNovaClientV26(test_consoles.TestConsolesNovaClient): + """Consoles functional tests for >=v2.6 api microversions.""" + + COMPUTE_API_VERSION = "2.6" + + def test_vnc_console_get(self): + self._test_vnc_console_get() + + def test_spice_console_get(self): + self._test_spice_console_get() + + def test_rdp_console_get(self): + self._test_rdp_console_get() + + def test_serial_console_get(self): + self._test_serial_console_get() diff --git a/novaclient/tests/unit/fixture_data/servers.py b/novaclient/tests/unit/fixture_data/servers.py index 5f45b528..595dcc9e 100644 --- a/novaclient/tests/unit/fixture_data/servers.py +++ b/novaclient/tests/unit/fixture_data/servers.py @@ -224,6 +224,10 @@ class Base(base.Fixture): json=self.post_servers, headers=self.json_headers) + self.requests.register_uri('POST', self.url('1234', 'remote-consoles'), + json=self.post_servers_1234_remote_consoles, + headers=self.json_headers) + self.requests.register_uri('POST', self.url('1234', 'action'), json=self.post_servers_1234_action, headers=self.json_headers) @@ -387,6 +391,20 @@ class V1(Base): return {'server': body} + def post_servers_1234_remote_consoles(self, request, context): + _body = '' + body = jsonutils.loads(request.body) + context.status_code = 202 + assert len(body.keys()) == 1 + assert 'remote_console' in body.keys() + assert 'protocol' in body['remote_console'].keys() + protocol = body['remote_console']['protocol'] + + _body = {'protocol': protocol, 'type': 'novnc', + 'url': 'http://example.com:6080/vnc_auto.html?token=XYZ'} + + return {'remote_console': _body} + def post_servers_1234_action(self, request, context): _body = '' body = jsonutils.loads(request.body) diff --git a/novaclient/tests/unit/v2/test_servers.py b/novaclient/tests/unit/v2/test_servers.py index f311ab7d..3b973538 100644 --- a/novaclient/tests/unit/v2/test_servers.py +++ b/novaclient/tests/unit/v2/test_servers.py @@ -20,6 +20,7 @@ import mock from oslo_serialization import jsonutils import six +from novaclient import api_versions from novaclient import exceptions from novaclient.tests.unit.fixture_data import client from novaclient.tests.unit.fixture_data import floatingips @@ -794,3 +795,41 @@ class ServersTest(utils.FixturedTestCase): s = self.cs.servers.get(1234) s.interface_detach('port-id') self.assert_called('DELETE', '/servers/1234/os-interface/port-id') + + +class ServersV26Test(ServersTest): + def setUp(self): + super(ServersV26Test, self).setUp() + self.cs.api_version = api_versions.APIVersion("2.6") + + def test_get_vnc_console(self): + s = self.cs.servers.get(1234) + s.get_vnc_console('fake') + self.assert_called('POST', '/servers/1234/remote-consoles') + + self.cs.servers.get_vnc_console(s, 'fake') + self.assert_called('POST', '/servers/1234/remote-consoles') + + def test_get_spice_console(self): + s = self.cs.servers.get(1234) + s.get_spice_console('fake') + self.assert_called('POST', '/servers/1234/remote-consoles') + + self.cs.servers.get_spice_console(s, 'fake') + self.assert_called('POST', '/servers/1234/remote-consoles') + + def test_get_serial_console(self): + s = self.cs.servers.get(1234) + s.get_serial_console('fake') + self.assert_called('POST', '/servers/1234/remote-consoles') + + self.cs.servers.get_serial_console(s, 'fake') + self.assert_called('POST', '/servers/1234/remote-consoles') + + def test_get_rdp_console(self): + s = self.cs.servers.get(1234) + s.get_rdp_console('fake') + self.assert_called('POST', '/servers/1234/remote-consoles') + + self.cs.servers.get_rdp_console(s, 'fake') + self.assert_called('POST', '/servers/1234/remote-consoles') diff --git a/novaclient/v2/servers.py b/novaclient/v2/servers.py index d21bc5fb..43e316ca 100644 --- a/novaclient/v2/servers.py +++ b/novaclient/v2/servers.py @@ -25,6 +25,7 @@ from oslo_utils import encodeutils import six from six.moves.urllib import parse +from novaclient import api_versions from novaclient import base from novaclient import crypto from novaclient.i18n import _ @@ -661,6 +662,7 @@ class ServerManager(base.BootingManagerWithFind): address = address.ip if hasattr(address, 'ip') else address self._action('removeFloatingIp', server, {'address': address}) + @api_versions.wraps('2.0', '2.5') def get_vnc_console(self, server, console_type): """ Get a vnc console for an instance @@ -672,6 +674,7 @@ class ServerManager(base.BootingManagerWithFind): return self._action('os-getVNCConsole', server, {'type': console_type})[1] + @api_versions.wraps('2.0', '2.5') def get_spice_console(self, server, console_type): """ Get a spice console for an instance @@ -683,6 +686,7 @@ class ServerManager(base.BootingManagerWithFind): return self._action('os-getSPICEConsole', server, {'type': console_type})[1] + @api_versions.wraps('2.0', '2.5') def get_rdp_console(self, server, console_type): """ Get a rdp console for an instance @@ -694,6 +698,7 @@ class ServerManager(base.BootingManagerWithFind): return self._action('os-getRDPConsole', server, {'type': console_type})[1] + @api_versions.wraps('2.0', '2.5') def get_serial_console(self, server, console_type): """ Get a serial console for an instance @@ -705,6 +710,54 @@ class ServerManager(base.BootingManagerWithFind): return self._action('os-getSerialConsole', server, {'type': console_type})[1] + @api_versions.wraps('2.6') + def get_vnc_console(self, server, console_type): + """ + Get a vnc console for an instance + + :param server: The :class:`Server` (or its ID) to add an IP to. + :param console_type: Type of vnc console to get ('novnc' or 'xvpvnc') + """ + + return self._console(server, + {'protocol': 'vnc', 'type': console_type})[1] + + @api_versions.wraps('2.6') + def get_spice_console(self, server, console_type): + """ + Get a spice console for an instance + + :param server: The :class:`Server` (or its ID) to add an IP to. + :param console_type: Type of spice console to get ('spice-html5') + """ + + return self._console(server, + {'protocol': 'spice', 'type': console_type})[1] + + @api_versions.wraps('2.6') + def get_rdp_console(self, server, console_type): + """ + Get a rdp console for an instance + + :param server: The :class:`Server` (or its ID) to add an IP to. + :param console_type: Type of rdp console to get ('rdp-html5') + """ + + return self._console(server, + {'protocol': 'rdp', 'type': console_type})[1] + + @api_versions.wraps('2.6') + def get_serial_console(self, server, console_type): + """ + Get a serial console for an instance + + :param server: The :class:`Server` (or its ID) to add an IP to. + :param console_type: Type of serial console to get ('serial') + """ + + return self._console(server, + {'protocol': 'serial', 'type': console_type})[1] + def get_password(self, server, private_key=None): """ Get admin password of an instance @@ -1277,3 +1330,11 @@ class ServerManager(base.BootingManagerWithFind): self.run_hooks('modify_body_for_action', body, **kwargs) 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) + return self.api.client.post(url, body=body) diff --git a/novaclient/v2/shell.py b/novaclient/v2/shell.py index c8a0598e..bb5a3f85 100644 --- a/novaclient/v2/shell.py +++ b/novaclient/v2/shell.py @@ -2303,6 +2303,16 @@ def do_volume_type_delete(cs, args): cs.volume_types.delete(args.id) +@api_versions.wraps('2.0', '2.5') +def console_dict_accessor(cs, data): + return data['console'] + + +@api_versions.wraps('2.6') +def console_dict_accessor(cs, data): + return data['remote_console'] + + @cliutils.arg('server', metavar='<server>', help=_('Name or ID of server.')) @cliutils.arg( 'console_type', @@ -2318,7 +2328,8 @@ def do_get_vnc_console(cs, args): self.type = console_dict['type'] self.url = console_dict['url'] - utils.print_list([VNCConsole(data['console'])], ['Type', 'Url']) + utils.print_list([VNCConsole(console_dict_accessor(cs, data))], + ['Type', 'Url']) @cliutils.arg('server', metavar='<server>', help=_('Name or ID of server.')) @@ -2336,7 +2347,8 @@ def do_get_spice_console(cs, args): self.type = console_dict['type'] self.url = console_dict['url'] - utils.print_list([SPICEConsole(data['console'])], ['Type', 'Url']) + utils.print_list([SPICEConsole(console_dict_accessor(cs, data))], + ['Type', 'Url']) @cliutils.arg('server', metavar='<server>', help=_('Name or ID of server.')) @@ -2354,7 +2366,8 @@ def do_get_rdp_console(cs, args): self.type = console_dict['type'] self.url = console_dict['url'] - utils.print_list([RDPConsole(data['console'])], ['Type', 'Url']) + utils.print_list([RDPConsole(console_dict_accessor(cs, data))], + ['Type', 'Url']) @cliutils.arg('server', metavar='<server>', help=_('Name or ID of server.')) @@ -2376,7 +2389,8 @@ def do_get_serial_console(cs, args): self.type = console_dict['type'] self.url = console_dict['url'] - utils.print_list([SerialConsole(data['console'])], ['Type', 'Url']) + utils.print_list([SerialConsole(console_dict_accessor(cs, data))], + ['Type', 'Url']) @cliutils.arg('server', metavar='<server>', help=_('Name or ID of server.')) |