Merge "libvirt: Acquire TCP ports for console during live migration" into stable/newton

This commit is contained in:
Jenkins 2017-03-17 16:07:41 +00:00 committed by Gerrit Code Review
commit 663b582ddc
2 changed files with 64 additions and 9 deletions

View File

@ -3588,15 +3588,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 = {arch.X86_64: vconfig.LibvirtConfigGuestSerial,
arch.S390: vconfig.LibvirtConfigGuestConsole,
@ -3605,19 +3611,22 @@ class LibvirtConnTestCase(test.NoDBTestCase):
for guest_arch, device_type in expected.items():
mock_get_arch.return_value = guest_arch
guest = vconfig.LibvirtConfigGuest()
drvr._create_serial_console_devices(guest, instance=None,
drvr._create_serial_console_devices(guest, instance=instance,
flavor={}, image_meta={})
self.assertEqual(1, 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'
@ -7841,24 +7850,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
@ -7873,7 +7885,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)

View File

@ -4080,6 +4080,19 @@ class LibvirtDriver(driver.ComputeDriver):
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)
@ -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,
@ -6448,6 +6474,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)
@ -6579,6 +6612,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'):