summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Riedemann <mriedem@us.ibm.com>2014-09-24 11:21:59 -0700
committerMatt Riedemann <mriedem@us.ibm.com>2014-09-25 13:59:48 -0700
commit867bdedf81533f283aae4de4488d54c254bb7f07 (patch)
treef8d82f4aae68aa4a9331e8588592015ea3d20812
parentd4ab4244b3d651f14c845ca53b57aae325c1d6fe (diff)
downloadnova-867bdedf81533f283aae4de4488d54c254bb7f07.tar.gz
Fallback to legacy live migration if config error
Commit ea7da5152cdca7ba674e2137c3899909995e2287 added a path to using migrateToURI2 for live migration if the version of libvirt used has the VIR_DOMAIN_XML_MIGRATABLE flag set. However, a bug in older versions of libvirt causes the live migration to fail because it's incorrectly validating the old and new domain xml's for ABI stability. Not all distros are running with the patched version of libvirt so add a check in place such that if we fail live migration on the new path with VIR_ERR_CONFIG_UNSUPPORTED, assume it's due to this issue and attempt the legacy migrateToURI call. Closes-Bug: #1362929 Related-Bug: #1279563 Change-Id: Ie82566121c2ed3a6d55919bc111358f4129cb404
-rw-r--r--nova/tests/virt/libvirt/test_driver.py55
-rw-r--r--nova/virt/libvirt/driver.py41
2 files changed, 89 insertions, 7 deletions
diff --git a/nova/tests/virt/libvirt/test_driver.py b/nova/tests/virt/libvirt/test_driver.py
index faf3f2a5fa..2bbe123037 100644
--- a/nova/tests/virt/libvirt/test_driver.py
+++ b/nova/tests/virt/libvirt/test_driver.py
@@ -5624,6 +5624,61 @@ class LibvirtConnTestCase(test.TestCase):
db.instance_destroy(self.context, instance_ref['uuid'])
+ @mock.patch.object(libvirt, 'VIR_DOMAIN_XML_MIGRATABLE', 8675, create=True)
+ def test_live_migration_raises_unsupported_config_exception(self):
+ # Tests that when migrateToURI2 fails with VIR_ERR_CONFIG_UNSUPPORTED,
+ # migrateToURI is used instead.
+
+ # Preparing data
+ instance_ref = fake_instance.fake_instance_obj(
+ self.context, **self.test_instance)
+
+ # Preparing mocks
+ vdmock = self.mox.CreateMock(libvirt.virDomain)
+ self.mox.StubOutWithMock(vdmock, 'migrateToURI2')
+ self.mox.StubOutWithMock(vdmock, 'migrateToURI')
+ _bandwidth = CONF.libvirt.live_migration_bandwidth
+ vdmock.XMLDesc(libvirt.VIR_DOMAIN_XML_MIGRATABLE).AndReturn(
+ FakeVirtDomain().XMLDesc(0))
+ unsupported_config_error = libvirt.libvirtError('ERR')
+ unsupported_config_error.err = (libvirt.VIR_ERR_CONFIG_UNSUPPORTED,)
+ # This is the first error we hit but since the error code is
+ # VIR_ERR_CONFIG_UNSUPPORTED we'll try migrateToURI.
+ vdmock.migrateToURI2(CONF.libvirt.live_migration_uri % 'dest', None,
+ mox.IgnoreArg(), mox.IgnoreArg(), None,
+ _bandwidth).AndRaise(unsupported_config_error)
+ # This is the second and final error that will actually kill the run,
+ # we use TestingException to make sure it's not the same libvirtError
+ # above.
+ vdmock.migrateToURI(CONF.libvirt.live_migration_uri % 'dest',
+ mox.IgnoreArg(), None,
+ _bandwidth).AndRaise(test.TestingException('oops'))
+
+ def fake_lookup(instance_name):
+ if instance_name == instance_ref.name:
+ return vdmock
+
+ self.create_fake_libvirt_mock(lookupByName=fake_lookup)
+
+ def fake_recover_method(context, instance, dest, block_migration):
+ pass
+
+ graphics_listen_addrs = {'vnc': '0.0.0.0', 'spice': '127.0.0.1'}
+ migrate_data = {'pre_live_migration_result':
+ {'graphics_listen_addrs': graphics_listen_addrs}}
+ conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
+
+ self.mox.StubOutWithMock(
+ conn, '_check_graphics_addresses_can_live_migrate')
+ conn._check_graphics_addresses_can_live_migrate(graphics_listen_addrs)
+ self.mox.ReplayAll()
+
+ # start test
+ self.assertRaises(test.TestingException, conn._live_migration,
+ self.context, instance_ref, 'dest', post_method=None,
+ recover_method=fake_recover_method,
+ migrate_data=migrate_data)
+
def test_rollback_live_migration_at_destination(self):
conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
with mock.patch.object(conn, "destroy") as mock_destroy:
diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py
index 6b1c1b7a98..913d0ea974 100644
--- a/nova/virt/libvirt/driver.py
+++ b/nova/virt/libvirt/driver.py
@@ -5351,13 +5351,40 @@ class LibvirtDriver(driver.ComputeDriver):
old_xml_str = dom.XMLDesc(migratable_flag)
new_xml_str = self._correct_listen_addr(old_xml_str,
listen_addrs)
-
- dom.migrateToURI2(CONF.libvirt.live_migration_uri % dest,
- None,
- new_xml_str,
- logical_sum,
- None,
- CONF.libvirt.live_migration_bandwidth)
+ try:
+ dom.migrateToURI2(CONF.libvirt.live_migration_uri % dest,
+ None,
+ new_xml_str,
+ logical_sum,
+ None,
+ CONF.libvirt.live_migration_bandwidth)
+ except libvirt.libvirtError as ex:
+ # NOTE(mriedem): There is a bug in older versions of
+ # libvirt where the VIR_DOMAIN_XML_MIGRATABLE flag causes
+ # virDomainDefCheckABIStability to not compare the source
+ # and target domain xml's correctly for the CPU model.
+ # We try to handle that error here and attempt the legacy
+ # migrateToURI path, which could fail if the console
+ # addresses are not correct, but in that case we have the
+ # _check_graphics_addresses_can_live_migrate check in place
+ # to catch it.
+ # TODO(mriedem): Remove this workaround when
+ # Red Hat BZ #1141838 is closed.
+ error_code = ex.get_error_code()
+ if error_code == libvirt.VIR_ERR_CONFIG_UNSUPPORTED:
+ LOG.warn(_LW('An error occurred trying to live '
+ 'migrate. Falling back to legacy live '
+ 'migrate flow. Error: %s'), ex,
+ instance=instance)
+ self._check_graphics_addresses_can_live_migrate(
+ listen_addrs)
+ dom.migrateToURI(
+ CONF.libvirt.live_migration_uri % dest,
+ logical_sum,
+ None,
+ CONF.libvirt.live_migration_bandwidth)
+ else:
+ raise
except Exception as e:
with excutils.save_and_reraise_exception():