Merge "Support the server side remote-console API changes"
This commit is contained in:
commit
a5363ae0d6
novaclient
@ -25,4 +25,4 @@ API_MIN_VERSION = api_versions.APIVersion("2.1")
|
|||||||
# when client supported the max version, and bumped sequentially, otherwise
|
# when client supported the max version, and bumped sequentially, otherwise
|
||||||
# the client may break due to server side new version may include some
|
# the client may break due to server side new version may include some
|
||||||
# backward incompatible change.
|
# 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,
|
json=self.post_servers,
|
||||||
headers=self.json_headers)
|
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'),
|
self.requests.register_uri('POST', self.url('1234', 'action'),
|
||||||
json=self.post_servers_1234_action,
|
json=self.post_servers_1234_action,
|
||||||
headers=self.json_headers)
|
headers=self.json_headers)
|
||||||
@ -387,6 +391,20 @@ class V1(Base):
|
|||||||
|
|
||||||
return {'server': body}
|
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):
|
def post_servers_1234_action(self, request, context):
|
||||||
_body = ''
|
_body = ''
|
||||||
body = jsonutils.loads(request.body)
|
body = jsonutils.loads(request.body)
|
||||||
|
@ -20,6 +20,7 @@ import mock
|
|||||||
from oslo_serialization import jsonutils
|
from oslo_serialization import jsonutils
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
from novaclient import api_versions
|
||||||
from novaclient import exceptions
|
from novaclient import exceptions
|
||||||
from novaclient.tests.unit.fixture_data import client
|
from novaclient.tests.unit.fixture_data import client
|
||||||
from novaclient.tests.unit.fixture_data import floatingips
|
from novaclient.tests.unit.fixture_data import floatingips
|
||||||
@ -794,3 +795,41 @@ class ServersTest(utils.FixturedTestCase):
|
|||||||
s = self.cs.servers.get(1234)
|
s = self.cs.servers.get(1234)
|
||||||
s.interface_detach('port-id')
|
s.interface_detach('port-id')
|
||||||
self.assert_called('DELETE', '/servers/1234/os-interface/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
|
import six
|
||||||
from six.moves.urllib import parse
|
from six.moves.urllib import parse
|
||||||
|
|
||||||
|
from novaclient import api_versions
|
||||||
from novaclient import base
|
from novaclient import base
|
||||||
from novaclient import crypto
|
from novaclient import crypto
|
||||||
from novaclient.i18n import _
|
from novaclient.i18n import _
|
||||||
@ -661,6 +662,7 @@ class ServerManager(base.BootingManagerWithFind):
|
|||||||
address = address.ip if hasattr(address, 'ip') else address
|
address = address.ip if hasattr(address, 'ip') else address
|
||||||
self._action('removeFloatingIp', server, {'address': address})
|
self._action('removeFloatingIp', server, {'address': address})
|
||||||
|
|
||||||
|
@api_versions.wraps('2.0', '2.5')
|
||||||
def get_vnc_console(self, server, console_type):
|
def get_vnc_console(self, server, console_type):
|
||||||
"""
|
"""
|
||||||
Get a vnc console for an instance
|
Get a vnc console for an instance
|
||||||
@ -672,6 +674,7 @@ class ServerManager(base.BootingManagerWithFind):
|
|||||||
return self._action('os-getVNCConsole', server,
|
return self._action('os-getVNCConsole', server,
|
||||||
{'type': console_type})[1]
|
{'type': console_type})[1]
|
||||||
|
|
||||||
|
@api_versions.wraps('2.0', '2.5')
|
||||||
def get_spice_console(self, server, console_type):
|
def get_spice_console(self, server, console_type):
|
||||||
"""
|
"""
|
||||||
Get a spice console for an instance
|
Get a spice console for an instance
|
||||||
@ -683,6 +686,7 @@ class ServerManager(base.BootingManagerWithFind):
|
|||||||
return self._action('os-getSPICEConsole', server,
|
return self._action('os-getSPICEConsole', server,
|
||||||
{'type': console_type})[1]
|
{'type': console_type})[1]
|
||||||
|
|
||||||
|
@api_versions.wraps('2.0', '2.5')
|
||||||
def get_rdp_console(self, server, console_type):
|
def get_rdp_console(self, server, console_type):
|
||||||
"""
|
"""
|
||||||
Get a rdp console for an instance
|
Get a rdp console for an instance
|
||||||
@ -694,6 +698,7 @@ class ServerManager(base.BootingManagerWithFind):
|
|||||||
return self._action('os-getRDPConsole', server,
|
return self._action('os-getRDPConsole', server,
|
||||||
{'type': console_type})[1]
|
{'type': console_type})[1]
|
||||||
|
|
||||||
|
@api_versions.wraps('2.0', '2.5')
|
||||||
def get_serial_console(self, server, console_type):
|
def get_serial_console(self, server, console_type):
|
||||||
"""
|
"""
|
||||||
Get a serial console for an instance
|
Get a serial console for an instance
|
||||||
@ -705,6 +710,54 @@ class ServerManager(base.BootingManagerWithFind):
|
|||||||
return self._action('os-getSerialConsole', server,
|
return self._action('os-getSerialConsole', server,
|
||||||
{'type': console_type})[1]
|
{'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):
|
def get_password(self, server, private_key=None):
|
||||||
"""
|
"""
|
||||||
Get admin password of an instance
|
Get admin password of an instance
|
||||||
@ -1277,3 +1330,11 @@ class ServerManager(base.BootingManagerWithFind):
|
|||||||
self.run_hooks('modify_body_for_action', body, **kwargs)
|
self.run_hooks('modify_body_for_action', body, **kwargs)
|
||||||
url = '/servers/%s/action' % base.getid(server)
|
url = '/servers/%s/action' % base.getid(server)
|
||||||
return self.api.client.post(url, body=body)
|
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)
|
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('server', metavar='<server>', help=_('Name or ID of server.'))
|
||||||
@cliutils.arg(
|
@cliutils.arg(
|
||||||
'console_type',
|
'console_type',
|
||||||
@ -2318,7 +2328,8 @@ def do_get_vnc_console(cs, args):
|
|||||||
self.type = console_dict['type']
|
self.type = console_dict['type']
|
||||||
self.url = console_dict['url']
|
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.'))
|
@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.type = console_dict['type']
|
||||||
self.url = console_dict['url']
|
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.'))
|
@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.type = console_dict['type']
|
||||||
self.url = console_dict['url']
|
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.'))
|
@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.type = console_dict['type']
|
||||||
self.url = console_dict['url']
|
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.'))
|
@cliutils.arg('server', metavar='<server>', help=_('Name or ID of server.'))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user