diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py old mode 100644 new mode 100755 index a4454333afc2..db1a692801f1 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -8275,6 +8275,61 @@ class LibvirtConnTestCase(test.NoDBTestCase): drvr._live_migration_uri('dest'), params=params, flags=0) + @mock.patch.object(fakelibvirt.virDomain, "migrateToURI3") + @mock.patch.object(host.Host, 'has_min_version', return_value=True) + @mock.patch('nova.virt.libvirt.guest.Guest.get_xml_desc', + return_value='') + def _test_live_migration_block_migration_flags(self, + device_names, expected_flags, + mock_old_xml, mock_min_version, mock_migrateToURI3): + migrate_data = objects.LibvirtLiveMigrateData( + graphics_listen_addr_vnc='0.0.0.0', + graphics_listen_addr_spice='0.0.0.0', + serial_listen_addr='127.0.0.1', + target_connect_addr=None, + bdms=[], + block_migration=True) + + dom = fakelibvirt.virDomain + guest = libvirt_guest.Guest(dom) + drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False) + drvr._parse_migration_flags() + + instance = objects.Instance(**self.test_instance) + drvr._live_migration_operation(self.context, instance, 'dest', + True, migrate_data, guest, + device_names) + + params = { + 'migrate_disks': device_names, + 'bandwidth': CONF.libvirt.live_migration_bandwidth, + 'destination_xml': b'', + } + mock_migrateToURI3.assert_called_once_with( + drvr._live_migration_uri('dest'), params=params, + flags=expected_flags) + + def test_live_migration_block_migration_with_devices(self): + device_names = ['vda'] + expected_flags = (fakelibvirt.VIR_MIGRATE_NON_SHARED_INC | + fakelibvirt.VIR_MIGRATE_UNDEFINE_SOURCE | + fakelibvirt.VIR_MIGRATE_PERSIST_DEST | + fakelibvirt.VIR_MIGRATE_PEER2PEER | + fakelibvirt.VIR_MIGRATE_LIVE) + + self._test_live_migration_block_migration_flags(device_names, + expected_flags) + + def test_live_migration_block_migration_all_filtered(self): + device_names = [] + expected_flags = (fakelibvirt.VIR_MIGRATE_UNDEFINE_SOURCE | + fakelibvirt.VIR_MIGRATE_PERSIST_DEST | + fakelibvirt.VIR_MIGRATE_PEER2PEER | + fakelibvirt.VIR_MIGRATE_LIVE) + + self._test_live_migration_block_migration_flags(device_names, + expected_flags) + @mock.patch.object(host.Host, 'has_min_version', return_value=True) @mock.patch.object(fakelibvirt.virDomain, "migrateToURI3") @mock.patch('nova.virt.libvirt.migration.get_updated_guest_xml', @@ -8307,9 +8362,14 @@ class LibvirtConnTestCase(test.NoDBTestCase): instance = objects.Instance(**self.test_instance) drvr._live_migration_operation(self.context, instance, 'dest', True, migrate_data, guest, disk_paths) + expected_flags = (fakelibvirt.VIR_MIGRATE_UNDEFINE_SOURCE | + fakelibvirt.VIR_MIGRATE_PERSIST_DEST | + fakelibvirt.VIR_MIGRATE_TUNNELLED | + fakelibvirt.VIR_MIGRATE_PEER2PEER | + fakelibvirt.VIR_MIGRATE_LIVE) mock_migrateToURI3.assert_called_once_with( drvr._live_migration_uri('dest'), - params=params, flags=159) + params=params, flags=expected_flags) def test_live_migration_raises_exception(self): # Confirms recover method is called when exceptions are raised. diff --git a/nova/virt/libvirt/guest.py b/nova/virt/libvirt/guest.py old mode 100644 new mode 100755 index ee74d90ec708..457d73bdf135 --- a/nova/virt/libvirt/guest.py +++ b/nova/virt/libvirt/guest.py @@ -641,6 +641,18 @@ class Guest(object): destination, flags=flags, bandwidth=bandwidth) else: if params: + # Due to a quirk in the libvirt python bindings, + # VIR_MIGRATE_NON_SHARED_INC with an empty migrate_disks is + # interpreted as "block migrate all writable disks" rather than + # "don't block migrate any disks". This includes attached + # volumes, which will potentially corrupt data on those + # volumes. Consequently we need to explicitly unset + # VIR_MIGRATE_NON_SHARED_INC if there are no disks to be block + # migrated. + if (flags & libvirt.VIR_MIGRATE_NON_SHARED_INC != 0 and + not params.get('migrate_disks')): + flags &= ~libvirt.VIR_MIGRATE_NON_SHARED_INC + # In migrateToURI3 these parameters are extracted from the # `params` dict if migrate_uri: