Merge "libvirt: enable live migration with serial console"

This commit is contained in:
Jenkins
2015-09-04 00:28:27 +00:00
committed by Gerrit Code Review
2 changed files with 101 additions and 4 deletions
+61 -1
View File
@@ -6197,7 +6197,7 @@ class LibvirtConnTestCase(test.NoDBTestCase):
self.assertFalse(drvr._live_migration_operation(
self.context, instance_ref, 'dest', False,
migrate_data, test_mock))
mupdate.assert_called_once_with(target_xml, volume, None)
mupdate.assert_called_once_with(target_xml, volume, None, None)
def test_update_volume_xml(self):
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
@@ -6332,6 +6332,63 @@ class LibvirtConnTestCase(test.NoDBTestCase):
volume_xml['volume'])
self.assertEqual(target_xml, etree.tostring(config))
@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):
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'/>"
"</console>"
"</devices>"
"</domain>")
initial_xml = xml_tmpl.format(addr='9.0.0.1')
target_xml = xml_tmpl.format(addr='9.0.0.12')
target_xml = etree.tostring(etree.fromstring(target_xml))
# Preparing mocks
mock_xml.return_value = initial_xml
mock_migrate.side_effect = fakelibvirt.libvirtError("ERR")
# start test
bandwidth = CONF.libvirt.live_migration_bandwidth
migrate_data = {'pre_live_migration_result':
{'graphics_listen_addrs':
{'vnc': '10.0.0.1', 'spice': '10.0.0.2'},
'serial_listen_addr': '9.0.0.12'}}
dom = fakelibvirt.virDomain
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
self.assertRaises(fakelibvirt.libvirtError,
drvr._live_migration_operation,
self.context, instance_ref, 'dest',
False, migrate_data, dom)
mock_xml.assert_called_once_with(
flags=fakelibvirt.VIR_DOMAIN_XML_MIGRATABLE)
mock_migrate.assert_called_once_with(
CONF.libvirt.live_migration_uri % 'dest',
None, target_xml, mock.ANY, None, bandwidth)
@mock.patch.object(fakelibvirt, 'VIR_DOMAIN_XML_MIGRATABLE', None,
create=True)
def test_live_migration_fails_with_serial_console_without_migratable(self):
self.compute = importutils.import_object(CONF.compute_manager)
instance_ref = self.test_instance
CONF.set_override("enabled", True, "serial_console")
dom = fakelibvirt.virDomain
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
self.assertRaises(exception.MigrationError,
drvr._live_migration_operation,
self.context, instance_ref, 'dest',
False, None, dom)
@mock.patch.object(fakelibvirt, 'VIR_DOMAIN_XML_MIGRATABLE', None,
create=True)
def test_live_migration_uses_migrateToURI_without_migratable_flag(self):
@@ -7230,6 +7287,7 @@ class LibvirtConnTestCase(test.NoDBTestCase):
target_ret = {
'graphics_listen_addrs': {'spice': '127.0.0.1', 'vnc': '127.0.0.1'},
'serial_listen_addr': '127.0.0.1',
'volume': {
'12345': {'connection_info': {u'data': {'device_path':
u'/dev/disk/by-path/ip-1.2.3.4:3260-iqn.abc.12345.opst-lun-X'},
@@ -7292,6 +7350,7 @@ class LibvirtConnTestCase(test.NoDBTestCase):
)
self.assertEqual({'graphics_listen_addrs': {'spice': '127.0.0.1',
'vnc': '127.0.0.1'},
'serial_listen_addr': '127.0.0.1',
'volume': {}}, res_data)
def test_pre_live_migration_vol_backed_works_correctly_mocked(self):
@@ -7344,6 +7403,7 @@ class LibvirtConnTestCase(test.NoDBTestCase):
target_ret = {
'graphics_listen_addrs': {'spice': '127.0.0.1',
'vnc': '127.0.0.1'},
'serial_listen_addr': '127.0.0.1',
'volume': {
'12345': {'connection_info': {u'data': {'device_path':
u'/dev/disk/by-path/ip-1.2.3.4:3260-iqn.abc.12345.opst-lun-X'},
+40 -3
View File
@@ -5420,7 +5420,7 @@ class LibvirtDriver(driver.ComputeDriver):
post_method, recover_method, block_migration,
migrate_data)
def _update_xml(self, xml_str, volume, listen_addrs):
def _update_xml(self, xml_str, volume, listen_addrs, serial_listen_addr):
xml_doc = etree.fromstring(xml_str)
if volume:
@@ -5429,6 +5429,10 @@ class LibvirtDriver(driver.ComputeDriver):
xml_doc = self._update_graphics_xml(xml_doc, listen_addrs)
else:
self._check_graphics_addresses_can_live_migrate(listen_addrs)
if serial_listen_addr:
xml_doc = self._update_serial_xml(xml_doc, serial_listen_addr)
else:
self._verify_serial_console_is_disabled()
return etree.tostring(xml_doc)
@@ -5489,6 +5493,17 @@ class LibvirtDriver(driver.ComputeDriver):
return xml_doc
def _update_serial_xml(self, xml_doc, listen_addr):
for dev in xml_doc.findall("./devices/serial[@type='tcp']/source"):
if dev.get('host') is not None:
dev.set('host', listen_addr)
for dev in xml_doc.findall("./devices/console[@type='tcp']/source"):
if dev.get('host') is not None:
dev.set('host', listen_addr)
return xml_doc
def _check_graphics_addresses_can_live_migrate(self, listen_addrs):
LOCAL_ADDRS = ('0.0.0.0', '127.0.0.1', '::', '::1')
@@ -5529,6 +5544,18 @@ class LibvirtDriver(driver.ComputeDriver):
' continue to listen on the current'
' addresses.'))
def _verify_serial_console_is_disabled(self):
if CONF.serial_console.enabled:
msg = _('Your libvirt version does not support the'
' VIR_DOMAIN_XML_MIGRATABLE flag or your'
' destination node does not support'
' retrieving listen addresses. In order'
' for live migration to work properly you'
' must either disable serial console or'
' upgrade your libvirt version.')
raise exception.MigrationError(reason=msg)
def _live_migration_operation(self, context, instance, dest,
block_migration, migrate_data, dom):
"""Invoke the live migration operation
@@ -5560,13 +5587,18 @@ class LibvirtDriver(driver.ComputeDriver):
'pre_live_migration_result', {})
listen_addrs = pre_live_migrate_data.get('graphics_listen_addrs')
volume = pre_live_migrate_data.get('volume')
serial_listen_addr = pre_live_migrate_data.get(
'serial_listen_addr')
migratable_flag = getattr(libvirt, 'VIR_DOMAIN_XML_MIGRATABLE',
None)
if (migratable_flag is None or
(listen_addrs is None and not volume)):
# TODO(alexs-h): These checks could be moved to the
# check_can_live_migrate_destination/source phase
self._check_graphics_addresses_can_live_migrate(listen_addrs)
self._verify_serial_console_is_disabled()
dom.migrateToURI(CONF.libvirt.live_migration_uri % dest,
logical_sum,
None,
@@ -5575,7 +5607,8 @@ class LibvirtDriver(driver.ComputeDriver):
old_xml_str = guest.get_xml_desc(dump_migratable=True)
new_xml_str = self._update_xml(old_xml_str,
volume,
listen_addrs)
listen_addrs,
serial_listen_addr)
try:
dom.migrateToURI2(CONF.libvirt.live_migration_uri % dest,
None,
@@ -5603,6 +5636,7 @@ class LibvirtDriver(driver.ComputeDriver):
instance=instance)
self._check_graphics_addresses_can_live_migrate(
listen_addrs)
self._verify_serial_console_is_disabled()
dom.migrateToURI(
CONF.libvirt.live_migration_uri % dest,
logical_sum,
@@ -6217,9 +6251,12 @@ class LibvirtDriver(driver.ComputeDriver):
greenthread.sleep(1)
# Store vncserver_listen and latest disk device info
res_data = {'graphics_listen_addrs': {}, 'volume': {}}
res_data = {'graphics_listen_addrs': {}, 'volume': {},
'serial_listen_addr': {}}
res_data['graphics_listen_addrs']['vnc'] = CONF.vnc.vncserver_listen
res_data['graphics_listen_addrs']['spice'] = CONF.spice.server_listen
res_data['serial_listen_addr'] = \
CONF.serial_console.proxyclient_address
for vol in block_device_mapping:
connection_info = vol['connection_info']
if connection_info.get('serial'):