summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2015-10-23 12:56:32 +0000
committerGerrit Code Review <review@openstack.org>2015-10-23 12:56:32 +0000
commita5363ae0d60d41feff23f6cca44fcd7aa9fc5b8b (patch)
tree86ee23171d47dd2e967baadc784d23cf9e0fe07c
parent5d5def785d0e9f39de8cfcda0fb720c9efe4f261 (diff)
parentcce7cd32775bc9d77a5ad57971be5d7c36e3aee5 (diff)
downloadpython-novaclient-a5363ae0d60d41feff23f6cca44fcd7aa9fc5b8b.tar.gz
Merge "Support the server side remote-console API changes"2.33.0
-rw-r--r--novaclient/__init__.py2
-rw-r--r--novaclient/tests/functional/v2/legacy/test_consoles.py67
-rw-r--r--novaclient/tests/functional/v2/test_consoles.py32
-rw-r--r--novaclient/tests/unit/fixture_data/servers.py18
-rw-r--r--novaclient/tests/unit/v2/test_servers.py39
-rw-r--r--novaclient/v2/servers.py61
-rw-r--r--novaclient/v2/shell.py22
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.'))