Merge "Support the server side remote-console API changes"

This commit is contained in:
Jenkins 2015-10-23 12:56:32 +00:00 committed by Gerrit Code Review
commit a5363ae0d6
7 changed files with 236 additions and 5 deletions

View File

@ -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")

View 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()

View 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()

View File

@ -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)

View File

@ -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')

View File

@ -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)

View File

@ -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.'))