Support the server side remote-console API changes
In microversion 2.6 the remote-console API was changed. See http://docs.openstack.org/developer/nova/api_microversion_history.html for details of those changes. This adds support for the new remote-console API. Change-Id: I67098d6ce8c71f3ac0073628fd3b0aa23cd81918 Closes-Bug: #1500688
This commit is contained in:
parent
28bf8ddb06
commit
cce7cd3277
@ -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")
|
||||
|
67
novaclient/tests/functional/v2/legacy/test_consoles.py
Normal file
67
novaclient/tests/functional/v2/legacy/test_consoles.py
Normal file
@ -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()
|
32
novaclient/tests/functional/v2/test_consoles.py
Normal file
32
novaclient/tests/functional/v2/test_consoles.py
Normal file
@ -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()
|
@ -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)
|
||||
|
@ -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')
|
||||
|
@ -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)
|
||||
|
@ -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.'))
|
||||
|
Loading…
Reference in New Issue
Block a user