From b67614fe878ea3b6bb6240f9989a21c2c3c0b2df Mon Sep 17 00:00:00 2001 From: lyanchih Date: Thu, 30 Jul 2015 09:16:16 +0000 Subject: [PATCH] libvirt: serial console ports count upper limit needs to be checked There is a limit of 4 serial ports on qemu_x86. If number of serial port over limit, qemu will throw error message with "libvirtError: internal error: process exited while connecting to monitor: qemu-system-x86_64: -device isa-serial,chardev=charserial4, id=serial4: Max. supported number of ISA serial ports is 4." We should check upper limit of serial console port. Change-Id: Id14c94dd658868037eeab1524a9984354cdb4071 Closes-Bug: 1478607 --- nova/exception.py | 5 ++++ nova/tests/unit/virt/libvirt/test_driver.py | 29 +++++++++++++++++++++ nova/virt/libvirt/driver.py | 25 +++++++++++++++--- 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/nova/exception.py b/nova/exception.py index 6ad203b3f338..8295e1cbaa11 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -1958,6 +1958,11 @@ class ImageSerialPortNumberExceedFlavorValue(Invalid): "ports passed in image meta.") +class SerialPortNumberLimitExceeded(Invalid): + msg_fmt = _("Maximum number of serial port exceeds %(allowed)d " + "for %(virt_type)s") + + class InvalidImageConfigDrive(Invalid): msg_fmt = _("Image's config drive option '%(config_drive)s' is invalid") diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index ae4504ce121a..e502360b447c 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -3318,6 +3318,35 @@ class LibvirtConnTestCase(test.NoDBTestCase): self.assertIsInstance(console_device, device_type) self.assertEqual("tcp", console_device.type) + @mock.patch('nova.virt.hardware.get_number_of_serial_ports', + return_value=4) + @mock.patch.object(libvirt_driver.libvirt_utils, 'get_arch', + side_effect=[arch.X86_64, arch.S390, arch.S390X]) + def test_create_serial_console_devices_with_limit_exceeded_based_on_arch( + self, mock_get_arch, mock_get_port_number): + self.flags(enabled=True, group='serial_console') + self.flags(virt_type="qemu", group='libvirt') + flavor = 'fake_flavor' + image_meta = objects.ImageMeta() + drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) + guest = vconfig.LibvirtConfigGuest() + self.assertRaises(exception.SerialPortNumberLimitExceeded, + drvr._create_serial_console_devices, + guest, None, flavor, image_meta) + mock_get_arch.assert_called_with(image_meta) + mock_get_port_number.assert_called_with(flavor, + image_meta) + + drvr._create_serial_console_devices(guest, None, flavor, image_meta) + mock_get_arch.assert_called_with(image_meta) + mock_get_port_number.assert_called_with(flavor, + image_meta) + + drvr._create_serial_console_devices(guest, None, flavor, image_meta) + mock_get_arch.assert_called_with(image_meta) + mock_get_port_number.assert_called_with(flavor, + image_meta) + @mock.patch('nova.console.serial.acquire_port') def test_get_guest_config_serial_console(self, acquire_port): self.flags(enabled=True, group='serial_console') diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index a8bafe8ae12f..82b2c225b601 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -491,6 +491,12 @@ MIN_QEMU_PPC64_VERSION = (2, 1, 0) # Names of the types that do not get compressed during migration NO_COMPRESSION_TYPES = ('qcow2',) + +# number of serial console limit +QEMU_MAX_SERIAL_PORTS = 4 +# Qemu supports 4 serial consoles, we remove 1 because of the PTY one defined +ALLOWED_QEMU_SERIAL_PORTS = QEMU_MAX_SERIAL_PORTS - 1 + # realtime suppport MIN_LIBVIRT_REALTIME_VERSION = (1, 2, 13) @@ -4182,6 +4188,13 @@ class LibvirtDriver(driver.ComputeDriver): hv.vapic = True guest.features.append(hv) + def _check_number_of_serial_console(self, num_ports): + virt_type = CONF.libvirt.virt_type + if (virt_type in ("kvm", "qemu") and + num_ports > ALLOWED_QEMU_SERIAL_PORTS): + raise exception.SerialPortNumberLimitExceeded( + allowed=ALLOWED_QEMU_SERIAL_PORTS, virt_type=virt_type) + def _create_serial_console_devices(self, guest, instance, flavor, image_meta): guest_arch = libvirt_utils.get_arch(image_meta) @@ -4189,11 +4202,15 @@ class LibvirtDriver(driver.ComputeDriver): if CONF.serial_console.enabled: num_ports = hardware.get_number_of_serial_ports( flavor, image_meta) + + if guest_arch in (arch.S390, arch.S390X): + console_cls = vconfig.LibvirtConfigGuestConsole + else: + console_cls = vconfig.LibvirtConfigGuestSerial + self._check_number_of_serial_console(num_ports) + for port in six.moves.range(num_ports): - if guest_arch in (arch.S390, arch.S390X): - console = vconfig.LibvirtConfigGuestConsole() - else: - console = vconfig.LibvirtConfigGuestSerial() + console = console_cls() console.port = port console.type = "tcp" console.listen_host = (