Merge "libvirt: Acquire TCP ports for console during live migration"
This commit is contained in:
commit
00b359ce14
@ -3623,15 +3623,21 @@ class LibvirtConnTestCase(test.NoDBTestCase):
|
||||
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 = {
|
||||
fields.Architecture.X86_64: vconfig.LibvirtConfigGuestSerial,
|
||||
@ -3644,13 +3650,17 @@ class LibvirtConnTestCase(test.NoDBTestCase):
|
||||
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',
|
||||
@ -3658,7 +3668,7 @@ class LibvirtConnTestCase(test.NoDBTestCase):
|
||||
fields.Architecture.S390,
|
||||
fields.Architecture.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'
|
||||
@ -3666,20 +3676,20 @@ class LibvirtConnTestCase(test.NoDBTestCase):
|
||||
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)
|
||||
@ -7915,24 +7925,27 @@ class LibvirtConnTestCase(test.NoDBTestCase):
|
||||
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
|
||||
@ -7947,7 +7960,8 @@ class LibvirtConnTestCase(test.NoDBTestCase):
|
||||
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)
|
||||
|
@ -4349,13 +4349,27 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
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)
|
||||
|
||||
@ -4558,8 +4572,7 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
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)
|
||||
@ -5950,12 +5963,25 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
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,
|
||||
@ -6464,6 +6490,13 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
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)
|
||||
@ -6591,6 +6624,15 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
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'):
|
||||
|
Loading…
Reference in New Issue
Block a user