console: add typed console objects

Adds typed console objects used by virt driver API to
return information about consoles.

Also updates virt drivers to use them.

Closes-Bug: #1361611
Change-Id: I8f6a857b88659ee30b4aa1a25ac52d7e01156a68
This commit is contained in:
Sahid Orentino Ferdjaoui 2014-08-26 11:00:34 +00:00
parent 9cf0c413d4
commit 0c3a47e573
14 changed files with 162 additions and 58 deletions

View File

@ -4233,9 +4233,8 @@ class ComputeManager(manager.Manager):
try:
# Retrieve connect info from driver, and then decorate with our
# access info token
connect_info = self.driver.get_vnc_console(context, instance)
connect_info['token'] = token
connect_info['access_url'] = access_url
console = self.driver.get_vnc_console(context, instance)
connect_info = console.get_connection_info(token, access_url)
except exception.InstanceNotFound:
if instance['vm_state'] != vm_states.BUILDING:
raise
@ -4270,9 +4269,8 @@ class ComputeManager(manager.Manager):
try:
# Retrieve connect info from driver, and then decorate with our
# access info token
connect_info = self.driver.get_spice_console(context, instance)
connect_info['token'] = token
connect_info['access_url'] = access_url
console = self.driver.get_spice_console(context, instance)
connect_info = console.get_connection_info(token, access_url)
except exception.InstanceNotFound:
if instance['vm_state'] != vm_states.BUILDING:
raise
@ -4306,9 +4304,8 @@ class ComputeManager(manager.Manager):
try:
# Retrieve connect info from driver, and then decorate with our
# access info token
connect_info = self.driver.get_rdp_console(context, instance)
connect_info['token'] = token
connect_info['access_url'] = access_url
console = self.driver.get_rdp_console(context, instance)
connect_info = console.get_connection_info(token, access_url)
except exception.InstanceNotFound:
if instance['vm_state'] != vm_states.BUILDING:
raise
@ -4330,7 +4327,7 @@ class ComputeManager(manager.Manager):
else:
console_info = self.driver.get_vnc_console(ctxt, instance)
return console_info['port'] == port
return console_info.port == port
@object_compat
@wrap_exception()

42
nova/console/type.py Normal file
View File

@ -0,0 +1,42 @@
# All Rights Reserved.
#
# 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.
class Console(object):
def __init__(self, host, port, internal_access_path=None):
self.host = host
self.port = port
self.internal_access_path = internal_access_path
def get_connection_info(self, token, access_url):
"""Returns an unreferenced dict with connection information."""
ret = dict(self.__dict__)
ret['token'] = token
ret['access_url'] = access_url
return ret
class ConsoleVNC(Console):
pass
class ConsoleRDP(Console):
pass
class ConsoleSpice(Console):
def __init__(self, host, port, tlsPort, internal_access_path=None):
super(ConsoleSpice, self).__init__(host, port, internal_access_path)
self.tlsPort = tlsPort

View File

@ -48,6 +48,7 @@ from nova.compute import task_states
from nova.compute import utils as compute_utils
from nova.compute import vm_states
from nova.conductor import manager as conductor_manager
from nova.console import type as ctype
from nova import context
from nova import db
from nova import exception
@ -3091,13 +3092,13 @@ class ComputeTestCase(BaseTestCase):
instance = self._create_fake_instance_obj()
def fake_driver_get_console(*args, **kwargs):
return {'host': "fake_host", 'port': "5900",
'internal_access_path': None}
return ctype.ConsoleVNC(host="fake_host", port=5900)
self.stubs.Set(self.compute.driver, "get_vnc_console",
fake_driver_get_console)
self.assertTrue(self.compute.validate_console_port(
context=self.context, instance=instance, port="5900",
context=self.context, instance=instance, port=5900,
console_type="novnc"))
def test_validate_console_port_spice(self):
@ -3106,13 +3107,13 @@ class ComputeTestCase(BaseTestCase):
instance = self._create_fake_instance_obj()
def fake_driver_get_console(*args, **kwargs):
return {'host': "fake_host", 'port': "5900",
'internal_access_path': None}
return ctype.ConsoleSpice(host="fake_host", port=5900, tlsPort=88)
self.stubs.Set(self.compute.driver, "get_spice_console",
fake_driver_get_console)
self.assertTrue(self.compute.validate_console_port(
context=self.context, instance=instance, port="5900",
context=self.context, instance=instance, port=5900,
console_type="spice-html5"))
def test_validate_console_port_rdp(self):
@ -3120,13 +3121,13 @@ class ComputeTestCase(BaseTestCase):
instance = self._create_fake_instance_obj()
def fake_driver_get_console(*args, **kwargs):
return {'host': "fake_host", 'port': "5900",
'internal_access_path': None}
return ctype.ConsoleRDP(host="fake_host", port=5900)
self.stubs.Set(self.compute.driver, "get_rdp_console",
fake_driver_get_console)
self.assertTrue(self.compute.validate_console_port(
context=self.context, instance=instance, port="5900",
context=self.context, instance=instance, port=5900,
console_type="rdp-html5"))
def test_validate_console_port_wrong_port(self):
@ -3135,8 +3136,8 @@ class ComputeTestCase(BaseTestCase):
instance = self._create_fake_instance_obj()
def fake_driver_get_console(*args, **kwargs):
return {'host': "fake_host", 'port': "5900",
'internal_access_path': None}
return ctype.ConsoleSpice(host="fake_host", port=5900, tlsPort=88)
self.stubs.Set(self.compute.driver, "get_vnc_console",
fake_driver_get_console)

View File

@ -0,0 +1,59 @@
# All Rights Reserved.
#
# 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 nova.console import type as ctype
from nova import test
class TypeTestCase(test.TestCase):
def setUp(self):
super(TypeTestCase, self).setUp()
def test_console(self):
c = ctype.Console(host='127.0.0.1', port=8945)
self.assertTrue(hasattr(c, 'host'))
self.assertTrue(hasattr(c, 'port'))
self.assertTrue(hasattr(c, 'internal_access_path'))
self.assertEqual('127.0.0.1', c.host)
self.assertEqual(8945, c.port)
self.assertIsNone(c.internal_access_path)
self.assertEqual({
'host': '127.0.0.1',
'port': 8945,
'internal_access_path': None,
'token': 'a-token',
'access_url': 'an-url'},
c.get_connection_info('a-token', 'an-url'))
def test_console_vnc(self):
c = ctype.ConsoleVNC(host='127.0.0.1', port=8945)
self.assertIsInstance(c, ctype.Console)
def test_console_rdp(self):
c = ctype.ConsoleRDP(host='127.0.0.1', port=8945)
self.assertIsInstance(c, ctype.Console)
def test_console_spice(self):
c = ctype.ConsoleSpice(host='127.0.0.1', port=8945, tlsPort=6547)
self.assertIsInstance(c, ctype.Console)
self.assertEqual(6547, c.tlsPort)
self.assertEqual(
6547, c.get_connection_info('a-token', 'an-url')['tlsPort'])

View File

@ -1832,9 +1832,9 @@ class HyperVAPITestCase(HyperVAPIBaseTestCase,
connect_info = self._conn.get_rdp_console(self._context, instance)
self._mox.VerifyAll()
self.assertEqual(CONF.my_ip, connect_info['host'])
self.assertEqual(fake_port, connect_info['port'])
self.assertEqual(fake_vm_id, connect_info['internal_access_path'])
self.assertEqual(CONF.my_ip, connect_info.host)
self.assertEqual(fake_port, connect_info.port)
self.assertEqual(fake_vm_id, connect_info.internal_access_path)
class VolumeOpsTestCase(HyperVAPIBaseTestCase):

View File

@ -8294,7 +8294,7 @@ Active: 8381604 kB
self.mox.ReplayAll()
conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
vnc_dict = conn.get_vnc_console(self.context, instance)
self.assertEqual(vnc_dict['port'], '5900')
self.assertEqual(vnc_dict.port, '5900')
def test_get_vnc_console_unavailable(self):
instance = self.create_instance_obj(self.context)
@ -8334,7 +8334,7 @@ Active: 8381604 kB
self.mox.ReplayAll()
conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
spice_dict = conn.get_spice_console(self.context, instance)
self.assertEqual(spice_dict['port'], '5950')
self.assertEqual(spice_dict.port, '5950')
def test_get_spice_console_unavailable(self):
instance = self.create_instance_obj(self.context)

View File

@ -22,6 +22,7 @@ import netaddr
import six
from nova.compute import manager
from nova.console import type as ctype
from nova import exception
from nova import objects
from nova.openstack.common import importutils
@ -539,27 +540,20 @@ class _VirtDriverTestCase(_FakeDriverBackendTestCase):
def test_get_vnc_console(self):
instance, network_info = self._get_running_instance(obj=True)
vnc_console = self.connection.get_vnc_console(self.ctxt, instance)
self.assertIn('internal_access_path', vnc_console)
self.assertIn('host', vnc_console)
self.assertIn('port', vnc_console)
self.assertIsInstance(vnc_console, ctype.ConsoleVNC)
@catch_notimplementederror
def test_get_spice_console(self):
instance_ref, network_info = self._get_running_instance()
spice_console = self.connection.get_spice_console(self.ctxt,
instance_ref)
self.assertIn('internal_access_path', spice_console)
self.assertIn('host', spice_console)
self.assertIn('port', spice_console)
self.assertIn('tlsPort', spice_console)
instance_ref)
self.assertIsInstance(spice_console, ctype.ConsoleSpice)
@catch_notimplementederror
def test_get_rdp_console(self):
instance_ref, network_info = self._get_running_instance()
rdp_console = self.connection.get_rdp_console(self.ctxt, instance_ref)
self.assertIn('internal_access_path', rdp_console)
self.assertIn('host', rdp_console)
self.assertIn('port', rdp_console)
self.assertIsInstance(rdp_console, ctype.ConsoleRDP)
@catch_notimplementederror
def test_get_console_pool_info(self):

View File

@ -443,7 +443,7 @@ class XenAPIVMTestCase(stubs.XenAPITestBase):
# Note(sulo): We don't care about session id in test
# they will always differ so strip that out
actual_path = console['internal_access_path'].split('&')[0]
actual_path = console.internal_access_path.split('&')[0]
expected_path = "/console?ref=%s" % str(vm_ref)
self.assertEqual(expected_path, actual_path)
@ -460,7 +460,7 @@ class XenAPIVMTestCase(stubs.XenAPITestBase):
# Note(sulo): We don't care about session id in test
# they will always differ so strip that out
actual_path = console['internal_access_path'].split('&')[0]
actual_path = console.internal_access_path.split('&')[0]
expected_path = "/console?ref=%s" % str(rescue_vm)
self.assertEqual(expected_path, actual_path)

View File

@ -373,6 +373,8 @@ class ComputeDriver(object):
:param context: security context
:param instance: nova.objects.instance.Instance
:returns an instance of console.type.ConsoleVNC
"""
raise NotImplementedError()
@ -381,6 +383,8 @@ class ComputeDriver(object):
:param context: security context
:param instance: nova.objects.instance.Instance
:returns an instance of console.type.ConsoleSpice
"""
raise NotImplementedError()
@ -389,6 +393,8 @@ class ComputeDriver(object):
:param context: security context
:param instance: nova.objects.instance.Instance
:returns an instance of console.type.ConsoleRDP
"""
raise NotImplementedError()

View File

@ -29,6 +29,7 @@ from oslo.config import cfg
from nova.compute import power_state
from nova.compute import task_states
from nova.console import type as ctype
from nova import db
from nova import exception
from nova.i18n import _
@ -337,20 +338,20 @@ class FakeDriver(driver.ComputeDriver):
return 'FAKE CONSOLE OUTPUT\nANOTHER\nLAST LINE'
def get_vnc_console(self, context, instance):
return {'internal_access_path': 'FAKE',
'host': 'fakevncconsole.com',
'port': 6969}
return ctype.ConsoleVNC(internal_access_path='FAKE',
host='fakevncconsole.com',
port=6969)
def get_spice_console(self, context, instance):
return {'internal_access_path': 'FAKE',
'host': 'fakespiceconsole.com',
'port': 6969,
'tlsPort': 6970}
return ctype.ConsoleSpice(internal_access_path='FAKE',
host='fakespiceconsole.com',
port=6969,
tlsPort=6970)
def get_rdp_console(self, context, instance):
return {'internal_access_path': 'FAKE',
'host': 'fakerdpconsole.com',
'port': 6969}
return ctype.ConsoleRDP(internal_access_path='FAKE',
host='fakerdpconsole.com',
port=6969)
def get_console_pool_info(self, console_type):
return {'address': '127.0.0.1',

View File

@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
from nova.console import type as ctype
from nova.openstack.common import log as logging
from nova.virt.hyperv import hostops
from nova.virt.hyperv import utilsfactory
@ -35,6 +36,5 @@ class RDPConsoleOps(object):
LOG.debug("RDP console: %(host)s:%(port)s, %(vm_id)s",
{"host": host, "port": port, "vm_id": vm_id})
return {'host': host,
'port': port,
'internal_access_path': vm_id}
return ctype.ConsoleRDP(
host=host, port=port, internal_access_path=vm_id)

View File

@ -56,6 +56,7 @@ from nova.compute import task_states
from nova.compute import utils as compute_utils
from nova.compute import vm_mode
from nova.console import serial as serial_console
from nova.console import type as ctype
from nova import context as nova_context
from nova import exception
from nova.i18n import _
@ -2652,7 +2653,7 @@ class LibvirtDriver(driver.ComputeDriver):
port = get_vnc_port_for_instance(instance.name)
host = CONF.vncserver_proxyclient_address
return {'host': host, 'port': port, 'internal_access_path': None}
return ctype.ConsoleVNC(host=host, port=port)
def get_spice_console(self, context, instance):
def get_spice_ports_for_instance(instance_name):
@ -2672,8 +2673,7 @@ class LibvirtDriver(driver.ComputeDriver):
ports = get_spice_ports_for_instance(instance['name'])
host = CONF.spice.server_proxyclient_address
return {'host': host, 'port': ports[0],
'tlsPort': ports[1], 'internal_access_path': None}
return ctype.ConsoleSpice(host=host, port=ports[0], tlsPort=ports[1])
@staticmethod
def _supports_direct_io(dirpath):

View File

@ -30,6 +30,7 @@ from nova import compute
from nova.compute import power_state
from nova.compute import task_states
from nova.compute import vm_states
from nova.console import type as ctype
from nova import context as nova_context
from nova import exception
from nova.i18n import _, _LE
@ -1291,7 +1292,7 @@ class VMwareVMOps(object):
"""Return connection info for a vnc console using ESX logic."""
vnc_console = self._get_vnc_console_connection(instance)
vnc_console['host'] = CONF.vmware.host_ip
return vnc_console
return ctype.ConsoleVNC(**vnc_console)
@staticmethod
def _get_machine_id_str(network_info):

View File

@ -33,6 +33,7 @@ from nova.compute import power_state
from nova.compute import task_states
from nova.compute import vm_mode
from nova.compute import vm_states
from nova.console import type as ctype
from nova import context as nova_context
from nova import exception
from nova.i18n import _
@ -1616,8 +1617,10 @@ class VMOps(object):
path = "/console?ref=%s&session_id=%s" % (str(vm_ref), session_id)
# NOTE: XS5.6sp2+ use http over port 80 for xenapi com
return {'host': CONF.vncserver_proxyclient_address, 'port': 80,
'internal_access_path': path}
return ctype.ConsoleVNC(
host=CONF.vncserver_proxyclient_address,
port=80,
internal_access_path=path)
def _vif_xenstore_data(self, vif):
"""convert a network info vif to injectable instance data."""