self.assertEqual(cfg.devices[5].type, "spice")
self.assertEqual(cfg.devices[6].type, "qxl")
+ @mock.patch.object(host.Host, 'get_guest')
+ @mock.patch.object(libvirt_driver.LibvirtDriver,
+ '_get_serial_ports_from_guest')
@mock.patch('nova.console.serial.acquire_port')
@mock.patch('nova.virt.hardware.get_number_of_serial_ports',
return_value=1)
@mock.patch.object(libvirt_driver.libvirt_utils, 'get_arch',)
def test_create_serial_console_devices_based_on_arch(self, mock_get_arch,
- mock_get_port_number,
- mock_acquire_port):
+ mock_get_port_number,
+ mock_acquire_port,
+ mock_ports,
+ mock_guest):
self.flags(enabled=True, group='serial_console')
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
+ instance = objects.Instance(**self.test_instance)
expected = {arch.X86_64: vconfig.LibvirtConfigGuestSerial,
arch.S390: vconfig.LibvirtConfigGuestConsole,
mock_get_arch.return_value = guest_arch
guest = vconfig.LibvirtConfigGuest()
- drvr._create_consoles(virt_type="kvm", guest=guest, log_path="",
- flavor={}, image_meta={}, caps=caps)
+ drvr._create_consoles(virt_type="kvm", guest=guest,
+ instance=instance, flavor={},
+ image_meta={}, caps=caps)
self.assertEqual(2, len(guest.devices))
console_device = guest.devices[0]
self.assertIsInstance(console_device, device_type)
self.assertEqual("tcp", console_device.type)
+ @mock.patch.object(host.Host, 'get_guest')
+ @mock.patch.object(libvirt_driver.LibvirtDriver,
+ '_get_serial_ports_from_guest')
@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, mock_get_arch, mock_get_port_number, mock_ports, mock_guest):
self.flags(enabled=True, group='serial_console')
self.flags(virt_type="qemu", group='libvirt')
flavor = 'fake_flavor'
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
caps = drvr._host.get_capabilities()
guest = vconfig.LibvirtConfigGuest()
- log_path = ""
+ instance = objects.Instance(**self.test_instance)
self.assertRaises(exception.SerialPortNumberLimitExceeded,
drvr._create_consoles,
- "kvm", guest, log_path, flavor, image_meta, caps)
+ "kvm", guest, instance, flavor, image_meta, caps)
mock_get_arch.assert_called_with(image_meta)
mock_get_port_number.assert_called_with(flavor,
image_meta)
- drvr._create_consoles("kvm", guest, log_path, flavor, image_meta, caps)
+ drvr._create_consoles("kvm", guest, instance, flavor, image_meta, caps)
mock_get_arch.assert_called_with(image_meta)
mock_get_port_number.assert_called_with(flavor,
image_meta)
- drvr._create_consoles("kvm", guest, log_path, flavor, image_meta, caps)
+ drvr._create_consoles("kvm", guest, instance, flavor, image_meta, caps)
mock_get_arch.assert_called_with(image_meta)
mock_get_port_number.assert_called_with(flavor,
image_meta)
drvr._get_volume_config)
self.assertEqual(target_xml, config)
+ @mock.patch.object(libvirt_driver.LibvirtDriver,
+ '_get_serial_ports_from_guest')
@mock.patch.object(fakelibvirt.virDomain, "migrateToURI2")
@mock.patch.object(fakelibvirt.virDomain, "XMLDesc")
def test_live_migration_update_serial_console_xml(self, mock_xml,
- mock_migrate):
+ mock_migrate, mock_get):
self.compute = importutils.import_object(CONF.compute_manager)
instance_ref = self.test_instance
xml_tmpl = ("<domain type='kvm'>"
"<devices>"
"<console type='tcp'>"
- "<source mode='bind' host='{addr}' service='10000'/>"
+ "<source mode='bind' host='{addr}' service='{port}'/>"
+ "<target type='serial' port='0'/>"
"</console>"
"</devices>"
"</domain>")
- initial_xml = xml_tmpl.format(addr='9.0.0.1')
+ initial_xml = xml_tmpl.format(addr='9.0.0.1', port='10100')
- target_xml = xml_tmpl.format(addr='9.0.0.12')
+ target_xml = xml_tmpl.format(addr='9.0.0.12', port='10200')
target_xml = etree.tostring(etree.fromstring(target_xml))
# Preparing mocks
serial_listen_addr='9.0.0.12',
target_connect_addr=None,
bdms=[],
- block_migration=False)
+ block_migration=False,
+ serial_listen_ports=[10200])
dom = fakelibvirt.virDomain
guest = libvirt_guest.Guest(dom)
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
else:
guest.os_boot_dev = blockinfo.get_boot_order(disk_info)
- def _create_consoles(self, virt_type, guest, log_path, flavor, image_meta,
+ def _create_consoles(self, virt_type, guest, instance, flavor, image_meta,
caps):
+ log_path = self._get_console_log_path(instance)
if virt_type in ("qemu", "kvm"):
# Create the serial console char devices
guest_arch = libvirt_utils.get_arch(image_meta)
if CONF.serial_console.enabled:
+ try:
+ # TODO(sahid): the guest param of this method should
+ # be renamed as guest_cfg then guest_obj to guest.
+ guest_obj = self._host.get_guest(instance)
+ if list(self._get_serial_ports_from_guest(guest_obj)):
+ # Serial port are already configured for instance that
+ # means we are in a context of migration.
+ return
+ except exception.InstanceNotFound:
+ LOG.debug(
+ "Instance does not exist yet on libvirt, we can "
+ "safely pass on looking for already defined serial "
+ "ports in its domain XML", instance=instance)
num_ports = hardware.get_number_of_serial_ports(
flavor, image_meta)
flavor, virt_type, self._host)
guest.add_device(config)
- log_path = self._get_console_log_path(instance)
- self._create_consoles(virt_type, guest, log_path, flavor,
+ self._create_consoles(virt_type, guest, instance, flavor,
image_meta, caps)
pointer = self._get_guest_pointer_model(guest.os_type, image_meta)
libvirt.VIR_MIGRATE_TUNNELLED != 0):
params.pop('migrate_disks')
+ # TODO(sahid): This should be in
+ # post_live_migration_at_source but no way to retrieve
+ # ports acquired on the host for the guest at this
+ # step. Since the domain is going to be removed from
+ # libvird on source host after migration, we backup the
+ # serial ports to release them if all went well.
+ serial_ports = []
+ if CONF.serial_console.enabled:
+ serial_ports = list(self._get_serial_ports_from_guest(guest))
+
guest.migrate(self._live_migration_uri(dest),
migrate_uri=migrate_uri,
flags=migration_flags,
params=params,
domain_xml=new_xml_str,
bandwidth=CONF.libvirt.live_migration_bandwidth)
+
+ for hostname, port in serial_ports:
+ serial_console.release_port(host=hostname, port=port)
except Exception as e:
with excutils.save_and_reraise_exception():
LOG.error(_LE("Live Migration failure: %s"), e,
is_shared_instance_path = True
if migrate_data:
is_shared_instance_path = migrate_data.is_shared_instance_path
+ if (migrate_data.obj_attr_is_set("serial_listen_ports")
+ and migrate_data.serial_listen_ports):
+ # Releases serial ports reserved.
+ for port in migrate_data.serial_listen_ports:
+ serial_console.release_port(
+ host=migrate_data.serial_listen_addr, port=port)
+
if not is_shared_instance_path:
instance_dir = libvirt_utils.get_instance_path_at_destination(
instance, migrate_data)
CONF.libvirt.live_migration_inbound_addr
migrate_data.supported_perf_events = self._supported_perf_events
+ migrate_data.serial_listen_ports = []
+ if CONF.serial_console.enabled:
+ num_ports = hardware.get_number_of_serial_ports(
+ instance.flavor, instance.image_meta)
+ for port in six.moves.range(num_ports):
+ migrate_data.serial_listen_ports.append(
+ serial_console.acquire_port(
+ migrate_data.serial_listen_addr))
+
for vol in block_device_mapping:
connection_info = vol['connection_info']
if connection_info.get('serial'):