diff --git a/nova/compute/manager.py b/nova/compute/manager.py index e89199cd4bf..eb6af7f4264 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -522,6 +522,10 @@ def update_compute_provider_status(self, context, rp_uuid, enabled): self.reportclient.set_traits_for_provider( context, rp_uuid, new_traits, generation=trait_info.generation) + def is_instance_storage_shared(self, context, instance, compute_host): + return self._compute._is_instance_storage_shared(context, instance, + compute_host) + class ComputeManager(manager.Manager): """Manages the running instances from creation to destruction.""" @@ -5629,7 +5633,7 @@ def _resize_instance( timeout, retry_interval = self._get_power_off_values( instance, clean_shutdown) disk_info = self.driver.migrate_disk_and_power_off( - context, instance, migration.dest_host, + context, instance, migration, flavor, network_info, block_device_info, timeout, retry_interval) diff --git a/nova/tests/unit/compute/test_virtapi.py b/nova/tests/unit/compute/test_virtapi.py index e477bf911cc..aed4d4fafda 100644 --- a/nova/tests/unit/compute/test_virtapi.py +++ b/nova/tests/unit/compute/test_virtapi.py @@ -56,6 +56,12 @@ def test_update_compute_provider_status(self): nova_context.get_admin_context(), uuids.rp_uuid, enabled=False) + def test_is_instance_storage_shared(self): + self.assertExpected('is_instance_storage_shared', + nova_context.get_admin_context(), + mock.sentinel.instance, + mock.sentinel.host) + class FakeVirtAPITest(VirtAPIBaseTest): @@ -74,6 +80,8 @@ def assertExpected(self, method, *args, **kwargs): self.virtapi.exit_wait_early(*args, **kwargs) elif method == 'update_compute_provider_status': self.virtapi.update_compute_provider_status(*args, **kwargs) + elif method == 'is_instance_storage_shared': + self.virtapi.is_instance_storage_shared(*args, **kwargs) else: self.fail("Unhandled FakeVirtAPI method: %s" % method) @@ -116,6 +124,9 @@ def _prepare_for_instance_event(self, instance, name, tag): self._events.append(m) return m + def _is_instance_storage_shared(self, context, instance, host): + return + class ComputeVirtAPITest(VirtAPIBaseTest): @@ -230,3 +241,15 @@ def test_update_compute_provider_status(self): self.virtapi.update_compute_provider_status( ctxt, uuids.rp_uuid, enabled=True) self.assertEqual(set(), self.compute.provider_traits[uuids.rp_uuid]) + + def test_is_instance_storage_shared(self): + ctxt = nova_context.get_admin_context() + + with mock.patch.object(self.compute, + '_is_instance_storage_shared') as mock_shared: + self.virtapi.is_instance_storage_shared(ctxt, + mock.sentinel.instance, + mock.sentinel.host) + mock_shared.assert_called_once_with(ctxt, + mock.sentinel.instance, + mock.sentinel.host) diff --git a/nova/tests/unit/virt/hyperv/test_driver.py b/nova/tests/unit/virt/hyperv/test_driver.py index 07f251390e2..56723920903 100644 --- a/nova/tests/unit/virt/hyperv/test_driver.py +++ b/nova/tests/unit/virt/hyperv/test_driver.py @@ -24,6 +24,7 @@ from os_win import exceptions as os_win_exc from nova import exception +from nova import objects from nova import safe_utils from nova.tests.unit import fake_instance from nova.tests.unit.virt.hyperv import test_base @@ -387,15 +388,17 @@ def test_unplug_vifs(self): mock.sentinel.instance, mock.sentinel.network_info) def test_migrate_disk_and_power_off(self): + migration = objects.Migration(dest_host='10.0.0.1', + dest_compute='mock-compute') self.driver.migrate_disk_and_power_off( - mock.sentinel.context, mock.sentinel.instance, mock.sentinel.dest, + mock.sentinel.context, mock.sentinel.instance, migration, mock.sentinel.flavor, mock.sentinel.network_info, mock.sentinel.block_device_info, mock.sentinel.timeout, mock.sentinel.retry_interval) migr_power_off = self.driver._migrationops.migrate_disk_and_power_off migr_power_off.assert_called_once_with( - mock.sentinel.context, mock.sentinel.instance, mock.sentinel.dest, + mock.sentinel.context, mock.sentinel.instance, migration.dest_host, mock.sentinel.flavor, mock.sentinel.network_info, mock.sentinel.block_device_info, mock.sentinel.timeout, mock.sentinel.retry_interval) diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index 23b7b060907..6538722b1ef 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -18512,28 +18512,16 @@ def test_set_cache_mode_invalid_object(self): drvr._set_cache_mode(fake_conf) self.assertEqual(fake_conf.driver_cache, 'fake') - @mock.patch('os.unlink') - @mock.patch.object(os.path, 'exists') + @mock.patch.object(fake.FakeVirtAPI, 'is_instance_storage_shared') def _test_shared_storage_detection(self, is_same, - mock_exists, mock_unlink): + mock_is_instance_storage_shared): drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) drvr.get_host_ip_addr = mock.MagicMock(return_value='bar') - mock_exists.return_value = is_same - with test.nested( - mock.patch.object(drvr._remotefs, 'create_file'), - mock.patch.object(drvr._remotefs, 'remove_file') - ) as (mock_rem_fs_create, mock_rem_fs_remove): - result = drvr._is_path_shared_with('host', '/path') - mock_rem_fs_create.assert_any_call('host', mock.ANY) - create_args, create_kwargs = mock_rem_fs_create.call_args - self.assertTrue(create_args[1].startswith('/path')) - if is_same: - mock_unlink.assert_called_once_with(mock.ANY) - else: - mock_rem_fs_remove.assert_called_with('host', mock.ANY) - remove_args, remove_kwargs = mock_rem_fs_remove.call_args - self.assertTrue(remove_args[1].startswith('/path')) - return result + mock_is_instance_storage_shared.return_value = is_same + return drvr._is_instance_storage_shared(None, + mock.sentinel.instance, + 'host', + mock.sentinel.dest_host) def test_shared_storage_detection_same_host(self): self.assertTrue(self._test_shared_storage_detection(True)) @@ -18541,19 +18529,16 @@ def test_shared_storage_detection_same_host(self): def test_shared_storage_detection_different_host(self): self.assertFalse(self._test_shared_storage_detection(False)) - @mock.patch.object(os, 'unlink') - @mock.patch.object(os.path, 'exists') - @mock.patch('oslo_concurrency.processutils.execute') + @mock.patch.object(fake.FakeVirtAPI, 'is_instance_storage_shared') @mock.patch.object(libvirt_driver.LibvirtDriver, 'get_host_ip_addr', return_value='foo') - def test_shared_storage_detection_easy(self, mock_get, mock_exec, - mock_exists, mock_unlink): + def test_shared_storage_detection_easy(self, mock_get, + mock_is_instance_storage_shared): drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) - self.assertTrue(drvr._is_path_shared_with('foo', '/path')) + self.assertTrue(drvr._is_instance_storage_shared( + None, mock.sentinel.instance, 'foo', mock.sentinel.dest_host)) mock_get.assert_called_once_with() - mock_exec.assert_not_called() - mock_exists.assert_not_called() - mock_unlink.assert_not_called() + mock_is_instance_storage_shared.assert_not_called() def test_store_pid_remove_pid(self): instance = objects.Instance(**self.test_instance) @@ -21579,13 +21564,20 @@ def _create_instance(self, params=None): return instance + def _create_migration(self, dest_host=None, dest_compute=None): + if not dest_compute: + dest_compute = 'mock-compute' + return objects.Migration( + dest_host=dest_host, + dest_compute=dest_compute) + @mock.patch(('nova.virt.libvirt.driver.LibvirtDriver.' '_get_instance_disk_info'), return_value=[]) @mock.patch('nova.virt.libvirt.driver.LibvirtDriver._destroy') @mock.patch('nova.virt.libvirt.driver.LibvirtDriver.get_host_ip_addr', return_value='10.0.0.1') @mock.patch(('nova.virt.libvirt.driver.LibvirtDriver.' - '_is_path_shared_with'), return_value=False) + '_is_instance_storage_shared'), return_value=False) @mock.patch('os.rename') @mock.patch('os.path.exists', return_value=True) @mock.patch('oslo_concurrency.processutils.execute', @@ -21600,10 +21592,11 @@ def test_migrate_disk_and_power_off_exception( ins_ref = self._create_instance() flavor = {'root_gb': 10, 'ephemeral_gb': 20} flavor_obj = objects.Flavor(**flavor) + migration = self._create_migration('10.0.0.2') self.assertRaises(test.TestingException, self.drvr.migrate_disk_and_power_off, - context.get_admin_context(), ins_ref, '10.0.0.2', + context.get_admin_context(), ins_ref, migration, flavor_obj, None) @mock.patch('nova.virt.libvirt.driver.LibvirtDriver.' @@ -21616,7 +21609,7 @@ def test_migrate_disk_and_power_off_exception( @mock.patch('nova.virt.libvirt.driver.LibvirtDriver.get_host_ip_addr', return_value='10.0.0.1') @mock.patch(('nova.virt.libvirt.driver.LibvirtDriver.' - '_is_path_shared_with'), return_value=False) + '_is_instance_storage_shared'), return_value=False) @mock.patch('os.rename') @mock.patch('os.path.exists', return_value=True) @mock.patch('oslo_concurrency.processutils.execute') @@ -21630,13 +21623,16 @@ def _test_migrate_disk_and_power_off( """ instance = self._create_instance(params=params_for_instance) + diff_host_migration = objects.Migration( + dest_host='10.0.0.2', + dest_compute='mock-compute') disk_info = list(fake_disk_info_byname(instance).values()) disk_info_text = jsonutils.dumps(disk_info) mock_get_disk_info.return_value = disk_info # dest is different host case out = self.drvr.migrate_disk_and_power_off( - ctxt, instance, '10.0.0.2', flavor_obj, None, + ctxt, instance, diff_host_migration, flavor_obj, None, block_device_info=block_device_info) mock_cleanup.assert_called_once() @@ -21646,9 +21642,13 @@ def _test_migrate_disk_and_power_off( instance.uuid, mock.ANY, mock.ANY, '10.0.0.2', mock.ANY, mock.ANY) mock_unplug_vifs.assert_called_once() mock_unplug_vifs.reset_mock() + # dest is same host case + same_host_migration = objects.Migration( + dest_host='10.0.0.1', + dest_compute='mock-compute') out = self.drvr.migrate_disk_and_power_off( - ctxt, instance, '10.0.0.1', flavor_obj, None, + ctxt, instance, same_host_migration, flavor_obj, None, block_device_info=block_device_info) mock_cleanup.assert_called_once() @@ -21656,6 +21656,7 @@ def _test_migrate_disk_and_power_off( mock_vtpm.assert_called_with( instance.uuid, mock.ANY, mock.ANY, '10.0.0.1', mock.ANY, mock.ANY) mock_unplug_vifs.assert_called_once() + return instance def test_migrate_disk_and_power_off(self): flavor = {'root_gb': 10, 'ephemeral_gb': 20} @@ -21732,6 +21733,7 @@ def test_migrate_disk_and_power_off_swap(self, mock_get_disk_info, # Original instance config instance = self._create_instance({'flavor': {'root_gb': 10, 'ephemeral_gb': 0}}) + migration = self._create_migration('10.0.0.1') disk_info = list(fake_disk_info_byname(instance).values()) mock_get_disk_info.return_value = disk_info @@ -21745,7 +21747,7 @@ def test_migrate_disk_and_power_off_swap(self, mock_get_disk_info, # Destination is same host out = drvr.migrate_disk_and_power_off(context.get_admin_context(), - instance, '10.0.0.1', + instance, migration, flavor_obj, None) mock_get_disk_info.assert_called_once_with(instance, None) @@ -21768,14 +21770,15 @@ def _test_migrate_disk_and_power_off_resize_check(self, expected_exc): """Test for nova.virt.libvirt.libvirt_driver.LibvirtConnection .migrate_disk_and_power_off. """ - instance = self._create_instance() + self.instance = self._create_instance() + self.migration = self._create_migration('10.0.0.1') flavor = {'root_gb': 10, 'ephemeral_gb': 20} flavor_obj = objects.Flavor(**flavor) # Migration is not implemented for LVM backed instances self.assertRaises(expected_exc, self.drvr.migrate_disk_and_power_off, - None, instance, '10.0.0.1', flavor_obj, None) + None, self.instance, self.migration, flavor_obj, None) @mock.patch('nova.virt.libvirt.driver.LibvirtDriver.unplug_vifs', new=mock.Mock()) @@ -21786,7 +21789,7 @@ def _test_migrate_disk_and_power_off_resize_check(self, expected_exc): @mock.patch('nova.virt.libvirt.driver.LibvirtDriver' '._get_instance_disk_info') @mock.patch('nova.virt.libvirt.driver.LibvirtDriver' - '._is_path_shared_with') + '._is_instance_storage_shared') def _test_migrate_disk_and_power_off_backing_file(self, shared_storage, mock_is_shared_storage, @@ -21811,9 +21814,10 @@ def fake_execute(*args, **kwargs): mock_execute.side_effect = fake_execute instance = self._create_instance() + migration = self._create_migration('10.0.0.2') out = self.drvr.migrate_disk_and_power_off( - context.get_admin_context(), instance, '10.0.0.2', + context.get_admin_context(), instance, migration, flavor_obj, None) dest = '10.0.0.2' if not shared_storage else None @@ -21839,7 +21843,7 @@ def test_migrate_disk_and_power_off_lvm(self): self._test_migrate_disk_and_power_off_resize_check(expected_exc) @mock.patch.object(libvirt_driver.LibvirtDriver, - '_is_path_shared_with', return_value=False) + '_is_instance_storage_shared', return_value=False) def test_migrate_disk_and_power_off_resize_cannot_ssh(self, mock_is_shared): def fake_execute(*args, **kwargs): @@ -21848,12 +21852,15 @@ def fake_execute(*args, **kwargs): expected_exc = exception.InstanceFaultRollback self._test_migrate_disk_and_power_off_resize_check(expected_exc) - mock_is_shared.assert_called_once_with('10.0.0.1', test.MatchType(str)) + mock_is_shared.assert_called_once_with(None, self.instance, + self.migration.dest_host, + self.migration.dest_compute) @mock.patch('nova.virt.libvirt.driver.LibvirtDriver' '._get_instance_disk_info') def test_migrate_disk_and_power_off_resize_error(self, mock_get_disk_info): instance = self._create_instance() + migration = self._create_migration('10.0.0.1') flavor = {'root_gb': 5, 'ephemeral_gb': 10} flavor_obj = objects.Flavor(**flavor) mock_get_disk_info.return_value = fake_disk_info_json(instance) @@ -21861,7 +21868,7 @@ def test_migrate_disk_and_power_off_resize_error(self, mock_get_disk_info): self.assertRaises( exception.InstanceFaultRollback, self.drvr.migrate_disk_and_power_off, - 'ctx', instance, '10.0.0.1', flavor_obj, None) + 'ctx', instance, migration, flavor_obj, None) @mock.patch('nova.virt.libvirt.driver.LibvirtDriver' '._get_instance_disk_info') @@ -21874,6 +21881,7 @@ def test_migrate_disk_and_power_off_resize_error_rbd(self, # will raise the same error). self.flags(images_type='rbd', group='libvirt') instance = self._create_instance() + migration = self._create_migration('10.0.0.1') flavor = {'root_gb': 5, 'ephemeral_gb': 20} flavor_obj = objects.Flavor(**flavor) mock_get_disk_info.return_value = [] @@ -21881,7 +21889,7 @@ def test_migrate_disk_and_power_off_resize_error_rbd(self, self.assertRaises( exception.InstanceFaultRollback, self.drvr.migrate_disk_and_power_off, - 'ctx', instance, '10.0.0.1', flavor_obj, None) + 'ctx', instance, migration, flavor_obj, None) @mock.patch('nova.virt.libvirt.driver.LibvirtDriver' '._get_instance_disk_info') @@ -21889,13 +21897,14 @@ def test_migrate_disk_and_power_off_resize_error_default_ephemeral( self, mock_get_disk_info): # Note(Mike_D): The size of this instance's ephemeral_gb is 20 gb. instance = self._create_instance() + migration = self._create_migration('10.0.0.1') flavor = {'root_gb': 10, 'ephemeral_gb': 0} flavor_obj = objects.Flavor(**flavor) mock_get_disk_info.return_value = fake_disk_info_json(instance) self.assertRaises(exception.InstanceFaultRollback, self.drvr.migrate_disk_and_power_off, - 'ctx', instance, '10.0.0.1', flavor_obj, None) + 'ctx', instance, migration, flavor_obj, None) @mock.patch('nova.virt.libvirt.driver.LibvirtDriver' '._get_instance_disk_info') @@ -21944,6 +21953,7 @@ def test_migrate_disk_and_power_off_resize_error_eph(self, mock_get, ] mock_get.return_value = mappings instance = self._create_instance() + migration = self._create_migration('10.0.0.1') # Old flavor, eph is 20, real disk is 3, target is 2, fail flavor = {'root_gb': 10, 'ephemeral_gb': 2} @@ -21953,7 +21963,7 @@ def test_migrate_disk_and_power_off_resize_error_eph(self, mock_get, self.assertRaises( exception.InstanceFaultRollback, self.drvr.migrate_disk_and_power_off, - 'ctx', instance, '10.0.0.1', flavor_obj, None) + 'ctx', instance, migration, flavor_obj, None) # Old flavor, eph is 20, real disk is 3, target is 4 flavor = {'root_gb': 10, 'ephemeral_gb': 4} @@ -21968,7 +21978,7 @@ def test_migrate_disk_and_power_off_resize_error_eph(self, mock_get, @mock.patch('nova.virt.libvirt.driver.LibvirtDriver._destroy') @mock.patch('nova.virt.libvirt.utils.get_instance_path') @mock.patch('nova.virt.libvirt.driver.LibvirtDriver' - '._is_path_shared_with') + '._is_instance_storage_shared') @mock.patch('nova.virt.libvirt.driver.LibvirtDriver' '._get_instance_disk_info') def test_migrate_disk_and_power_off_resize_copy_disk_info( @@ -21976,6 +21986,7 @@ def test_migrate_disk_and_power_off_resize_copy_disk_info( mock_copy, mock_execute, mock_rename): instance = self._create_instance() + migration = self._create_migration() disk_info = list(fake_disk_info_byname(instance).values()) instance_base = os.path.dirname(disk_info[0]['path']) flavor = {'root_gb': 10, 'ephemeral_gb': 25} @@ -21994,13 +22005,13 @@ def test_migrate_disk_and_power_off_resize_copy_disk_info( mock_exists.side_effect = \ lambda path: path == src_disk_info_path self.drvr.migrate_disk_and_power_off(context.get_admin_context(), - instance, mock.sentinel, + instance, migration, flavor_obj, None) self.assertTrue(mock_exists.called) dst_disk_info_path = os.path.join(instance_base, 'disk.info') mock_copy.assert_any_call(src_disk_info_path, dst_disk_info_path, - host=mock.sentinel, on_execute=mock.ANY, + host=migration.dest_host, on_execute=mock.ANY, on_completion=mock.ANY) def test_wait_for_running(self): diff --git a/nova/tests/unit/virt/test_virt_drivers.py b/nova/tests/unit/virt/test_virt_drivers.py index 9b10495f81f..fa7ff04e3aa 100644 --- a/nova/tests/unit/virt/test_virt_drivers.py +++ b/nova/tests/unit/virt/test_virt_drivers.py @@ -300,7 +300,7 @@ def test_migrate_disk_and_power_off(self): instance_ref, network_info = self._get_running_instance() flavor_ref = test_utils.get_test_flavor() self.connection.migrate_disk_and_power_off( - self.ctxt, instance_ref, 'dest_host', flavor_ref, + self.ctxt, instance_ref, mock.sentinel.migration, flavor_ref, network_info) @catch_notimplementederror diff --git a/nova/tests/unit/virt/vmwareapi/test_driver_api.py b/nova/tests/unit/virt/vmwareapi/test_driver_api.py index 4558b710e22..b07baca6c44 100644 --- a/nova/tests/unit/virt/vmwareapi/test_driver_api.py +++ b/nova/tests/unit/virt/vmwareapi/test_driver_api.py @@ -2612,10 +2612,13 @@ def test_detach_interface_with_exception(self, mock_get_device, def test_resize_to_smaller_disk(self, mock_update_cached_instances): self._create_vm(flavor='m1.large') flavor = self._get_flavor_by_name('m1.small') - fake_dest = '1.0|vcenter-uuid' + migration = objects.Migration( + dest_host='1.0|vcenter-uuid' + ) + self.assertRaises(exception.InstanceFaultRollback, self.conn.migrate_disk_and_power_off, self.context, - self.instance, fake_dest, flavor, None) + self.instance, migration, flavor, None) @mock.patch.object(vmops.VMwareVMOps, 'update_cached_instances') def test_spawn_attach_volume_vmdk(self, mock_update_cached_instances): diff --git a/nova/virt/driver.py b/nova/virt/driver.py index b11bb2a98d8..7eb1ec0a1f3 100644 --- a/nova/virt/driver.py +++ b/nova/virt/driver.py @@ -688,7 +688,7 @@ def detach_interface(self, context, instance, vif): """ raise NotImplementedError() - def migrate_disk_and_power_off(self, context, instance, dest, + def migrate_disk_and_power_off(self, context, instance, migration, flavor, network_info, block_device_info=None, timeout=0, retry_interval=0): @@ -697,8 +697,8 @@ def migrate_disk_and_power_off(self, context, instance, dest, :param nova.objects.instance.Instance instance: The instance whose disk should be migrated. - :param str dest: - The IP address of the destination host. + :param nova.objects.migration.Migration migration: + The migration to be executed :param nova.objects.flavor.Flavor flavor: The flavor of the instance whose disk get migrated. :param nova.network.model.NetworkInfo network_info: @@ -709,6 +709,8 @@ def migrate_disk_and_power_off(self, context, instance, dest, The time in seconds to wait for the guest OS to shutdown. :param int retry_interval: How often to signal guest while waiting for it to shutdown. + :param str dest_compute: + The name of the destination compute-host :return: A list of disk information dicts in JSON format. :rtype: str diff --git a/nova/virt/fake.py b/nova/virt/fake.py index 11be13ef9ef..9695eb425c9 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -250,7 +250,7 @@ def unrescue( def poll_rebooting_instances(self, timeout, instances): pass - def migrate_disk_and_power_off(self, context, instance, dest, + def migrate_disk_and_power_off(self, context, instance, migration, flavor, network_info, block_device_info=None, timeout=0, retry_interval=0): @@ -670,6 +670,9 @@ def exit_wait_early(self, events): def update_compute_provider_status(self, context, rp_uuid, enabled): pass + def is_instance_storage_shared(self, context, instance, host=None): + pass + class FakeComputeVirtAPI(FakeVirtAPI): def __init__(self, compute): diff --git a/nova/virt/hyperv/driver.py b/nova/virt/hyperv/driver.py index 350e59e295c..242009c7705 100644 --- a/nova/virt/hyperv/driver.py +++ b/nova/virt/hyperv/driver.py @@ -299,12 +299,14 @@ def unplug_vifs(self, instance, network_info): """Unplug VIFs from networks.""" self._vmops.unplug_vifs(instance, network_info) - def migrate_disk_and_power_off(self, context, instance, dest, + def migrate_disk_and_power_off(self, context, instance, migration, flavor, network_info, block_device_info=None, timeout=0, retry_interval=0): + dest_host = migration.dest_host return self._migrationops.migrate_disk_and_power_off(context, - instance, dest, + instance, + dest_host, flavor, network_info, block_device_info, diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index 85a4b463ed2..9aaa46d8bbc 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -11036,28 +11036,20 @@ def _get_disk_size_reserved_for_image_cache(self): return compute_utils.convert_mb_to_ceil_gb( self.image_cache_manager.get_disk_usage() / 1024.0 / 1024.0) - def _is_path_shared_with(self, dest, path): + def _is_instance_storage_shared(self, context, instance, dest, + dest_compute): # NOTE (rmk): There are two methods of determining whether we are # on the same filesystem: the source and dest IP are the - # same, or we create a file on the dest system via SSH - # and check whether the source system can also see it. - shared_path = (dest == self.get_host_ip_addr()) - if not shared_path: - tmp_file = uuidutils.generate_uuid(dashed=False) + '.tmp' - tmp_path = os.path.join(path, tmp_file) + # same... + if dest == self.get_host_ip_addr(): + return True - try: - self._remotefs.create_file(dest, tmp_path) - if os.path.exists(tmp_path): - shared_path = True - os.unlink(tmp_path) - else: - self._remotefs.remove_file(dest, tmp_path) - except Exception: - pass - return shared_path + # NOTE (fwiesel): Or we rely on the drivers api pair + # check_instance_shared_storage_local / check_instance_shared_storage + return self.virtapi.is_instance_storage_shared(context, instance, + dest_compute) - def migrate_disk_and_power_off(self, context, instance, dest, + def migrate_disk_and_power_off(self, context, instance, migration, flavor, network_info, block_device_info=None, timeout=0, retry_interval=0): @@ -11095,7 +11087,12 @@ def migrate_disk_and_power_off(self, context, instance, dest, # shared storage for instance dir (eg. NFS). inst_base = libvirt_utils.get_instance_path(instance) inst_base_resize = inst_base + "_resize" - shared_instance_path = self._is_path_shared_with(dest, inst_base) + dest = migration.dest_host + dest_compute = migration.dest_compute + shared_instance_path = self._is_instance_storage_shared(context, + instance, + dest, + dest_compute) # try to create the directory on the remote compute node # if this fails we pass the exception up the stack so we can catch diff --git a/nova/virt/virtapi.py b/nova/virt/virtapi.py index dad1197d8cc..eec9ffd3799 100644 --- a/nova/virt/virtapi.py +++ b/nova/virt/virtapi.py @@ -34,3 +34,6 @@ def update_compute_provider_status(self, context, rp_uuid, enabled): the trait would be added. """ raise NotImplementedError() + + def is_instance_storage_shared(self, context, instance, host=None): + raise NotImplementedError() diff --git a/nova/virt/vmwareapi/driver.py b/nova/virt/vmwareapi/driver.py index 5b444962731..95c1ab80399 100644 --- a/nova/virt/vmwareapi/driver.py +++ b/nova/virt/vmwareapi/driver.py @@ -292,7 +292,7 @@ def list_instances(self): """List VM instances from the single compute node.""" return self._vmops.list_instances() - def migrate_disk_and_power_off(self, context, instance, dest, + def migrate_disk_and_power_off(self, context, instance, migration, flavor, network_info, block_device_info=None, timeout=0, retry_interval=0): @@ -300,6 +300,7 @@ def migrate_disk_and_power_off(self, context, instance, dest, off the instance before the end. """ # TODO(PhilDay): Add support for timeout (clean shutdown) + dest = migration.dest_host return self._vmops.migrate_disk_and_power_off( context, instance, dest, flavor, network_info, block_device_info)