From 19bf42a582402ee072645a335f35c205eb5a021b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Ribaud?= Date: Tue, 4 Oct 2022 16:59:06 +0200 Subject: [PATCH] Support rescuing an instance with shares Allow to rescue an instance with shares attached. Manila is the OpenStack Shared Filesystems service. These series of patches implement changes required in Nova to allow the shares provided by Manila to be associated with and attached to instances using virtiofs. Implements: blueprint libvirt-virtiofs-attach-manila-shares Change-Id: I27a408b5af6103c60947fb2c4415cafe11f37f61 --- nova/compute/manager.py | 6 +- nova/tests/unit/compute/test_compute.py | 137 ++++++++++++++++++-- nova/tests/unit/compute/test_compute_mgr.py | 12 +- nova/tests/unit/virt/ironic/test_driver.py | 13 +- nova/tests/unit/virt/libvirt/test_driver.py | 28 ++-- nova/tests/unit/virt/test_virt_drivers.py | 6 +- nova/virt/driver.py | 4 +- nova/virt/fake.py | 2 +- nova/virt/ironic/driver.py | 4 +- nova/virt/libvirt/driver.py | 11 +- nova/virt/vmwareapi/driver.py | 2 +- 11 files changed, 185 insertions(+), 40 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 4e6616bdef4d..9b1a201541d7 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -5038,6 +5038,8 @@ class ComputeManager(manager.Manager): block_device_info = self._get_instance_block_device_info( context, instance, bdms=bdms) + share_info = self._get_share_info(context, instance) + extra_usage_info = {'rescue_image_name': self._get_image_name(rescue_image_meta)} self._notify_about_instance_usage(context, instance, @@ -5050,9 +5052,11 @@ class ComputeManager(manager.Manager): try: self._power_off_instance(context, instance, clean_shutdown) + self._mount_all_shares(context, instance, share_info) + self.driver.rescue(context, instance, network_info, rescue_image_meta, admin_password, - block_device_info) + block_device_info, share_info) except Exception as e: LOG.exception("Error trying to Rescue Instance", instance=instance) diff --git a/nova/tests/unit/compute/test_compute.py b/nova/tests/unit/compute/test_compute.py index 995380e52df9..2f391109e3df 100644 --- a/nova/tests/unit/compute/test_compute.py +++ b/nova/tests/unit/compute/test_compute.py @@ -2417,7 +2417,7 @@ class ComputeTestCase(BaseTestCase, 'unrescued': False} def fake_rescue(self, context, instance_ref, network_info, image_meta, - rescue_password, block_device_info): + rescue_password, block_device_info, share_info): called['rescued'] = True self.stub_out('nova.virt.fake.FakeDriver.rescue', fake_rescue) @@ -2448,7 +2448,7 @@ class ComputeTestCase(BaseTestCase, def test_rescue_notifications(self, mock_context, mock_notify): # Ensure notifications on instance rescue. def fake_rescue(self, context, instance_ref, network_info, image_meta, - rescue_password, block_device_info): + rescue_password, block_device_info, share_info): pass self.stub_out('nova.virt.fake.FakeDriver.rescue', fake_rescue) @@ -2545,13 +2545,14 @@ class ComputeTestCase(BaseTestCase, self.compute.terminate_instance(self.context, instance, []) + @mock.patch('nova.compute.manager.ComputeManager._get_share_info') @mock.patch.object(nova.compute.manager.ComputeManager, '_get_instance_block_device_info') @mock.patch.object(fake.FakeDriver, 'power_off') @mock.patch.object(fake.FakeDriver, 'rescue') @mock.patch.object(compute_manager.ComputeManager, '_get_rescue_image') def test_rescue_handle_err(self, mock_get, mock_rescue, mock_power_off, - mock_get_block_info): + mock_get_block_info, mock_get_share_info): # If the driver fails to rescue, instance state should got to ERROR # and the exception should be converted to InstanceNotRescuable inst_obj = self._create_fake_instance_obj() @@ -2562,6 +2563,9 @@ class ComputeTestCase(BaseTestCase, expected_message = ('Instance %s cannot be rescued: ' 'Driver Error: Try again later' % inst_obj.uuid) + share_info = objects.ShareMappingList() + mock_get_share_info.return_value = share_info + with testtools.ExpectedException( exception.InstanceNotRescuable, expected_message): self.compute.rescue_instance( @@ -2573,18 +2577,25 @@ class ComputeTestCase(BaseTestCase, mock_get.assert_called_once_with(mock.ANY, inst_obj, mock.ANY) mock_rescue.assert_called_once_with(mock.ANY, inst_obj, [], mock.ANY, 'password', - mock.sentinel.block_device_info) + mock.sentinel.block_device_info, + share_info) + @mock.patch.object(nova.virt.fake.FakeDriver, "mount_share") + @mock.patch('nova.compute.manager.ComputeManager._get_share_info') @mock.patch.object(nova.compute.manager.ComputeManager, '_get_instance_block_device_info') @mock.patch.object(image_api.API, "get") @mock.patch.object(fake.FakeDriver, 'power_off') @mock.patch.object(nova.virt.fake.FakeDriver, "rescue") def test_rescue_with_image_specified(self, mock_rescue, mock_power_off, - mock_image_get, mock_get_block_info): + mock_image_get, mock_get_block_info, mock_get_share_info, + mock_drv_mount): image_ref = uuids.image_instance rescue_image_meta = {} params = {"task_state": task_states.RESCUING} + share_info = objects.ShareMappingList() + mock_get_share_info.return_value = share_info + instance = self._create_fake_instance_obj(params=params) ctxt = context.get_admin_context() @@ -2599,24 +2610,30 @@ class ComputeTestCase(BaseTestCase, clean_shutdown=True) mock_image_get.assert_called_with(ctxt, image_ref) + mock_drv_mount.assert_not_called() mock_rescue.assert_called_with(ctxt, instance, [], test.MatchType(objects.ImageMeta), 'password', - mock.sentinel.block_device_info) + mock.sentinel.block_device_info, + share_info) self.compute.terminate_instance(ctxt, instance, []) + @mock.patch.object(nova.virt.fake.FakeDriver, "mount_share") + @mock.patch('nova.compute.manager.ComputeManager._get_share_info') @mock.patch.object(nova.compute.manager.ComputeManager, '_get_instance_block_device_info') @mock.patch.object(image_api.API, "get") @mock.patch.object(fake.FakeDriver, 'power_off') @mock.patch.object(nova.virt.fake.FakeDriver, "rescue") - def test_rescue_with_base_image_when_image_not_specified(self, - mock_rescue, mock_power_off, mock_image_get, mock_get_block_info): - image_ref = FAKE_IMAGE_REF - system_meta = {"image_base_image_ref": image_ref} + def test_rescue_with_image_specified_and_share( + self, mock_rescue, mock_power_off, mock_image_get, mock_get_block_info, + mock_get_share_info, mock_drv_mount): + image_ref = uuids.image_instance rescue_image_meta = {} - params = {"task_state": task_states.RESCUING, - "system_metadata": system_meta} + params = {"task_state": task_states.RESCUING} + share_info = self.fake_share_info() + mock_get_share_info.return_value = share_info + instance = self._create_fake_instance_obj(params=params) ctxt = context.get_admin_context() @@ -2626,6 +2643,99 @@ class ComputeTestCase(BaseTestCase, mock_get_block_info.return_value = mock.sentinel.block_device_info mock_image_get.return_value = rescue_image_meta + mock_get_share_info.return_value = share_info + + self.compute.rescue_instance(mock_context, instance=instance, + rescue_password="password", rescue_image_ref=image_ref, + clean_shutdown=True) + + mock_image_get.assert_called_with(ctxt, image_ref) + mock_drv_mount.assert_called_with(ctxt, instance, share_info[0]) + mock_rescue.assert_called_with( + ctxt, + instance, + [], + test.MatchType(objects.ImageMeta), + "password", + mock.sentinel.block_device_info, + share_info, + ) + self.compute.terminate_instance(ctxt, instance, []) + + @mock.patch('nova.objects.instance_fault.InstanceFault.create') + @mock.patch.object(nova.virt.fake.FakeDriver, "mount_share") + @mock.patch('nova.compute.manager.ComputeManager._get_share_info') + @mock.patch.object(nova.compute.manager.ComputeManager, + '_get_instance_block_device_info') + @mock.patch.object(image_api.API, "get") + @mock.patch.object(fake.FakeDriver, 'power_off') + @mock.patch.object(nova.virt.fake.FakeDriver, "rescue") + def test_rescue_with_image_specified_and_mount_error( + self, mock_rescue, mock_power_off, mock_image_get, mock_get_block_info, + mock_get_share_info, mock_drv_mount, mock_db_fault): + image_ref = uuids.image_instance + rescue_image_meta = {} + params = {"task_state": task_states.RESCUING} + share_info = self.fake_share_info() + mock_get_share_info.return_value = share_info + + instance = self._create_fake_instance_obj(params=params) + + ctxt = context.get_admin_context() + mock_context = mock.Mock() + mock_context.elevated.return_value = ctxt + + mock_get_block_info.return_value = mock.sentinel.block_device_info + mock_image_get.return_value = rescue_image_meta + + mock_drv_mount.side_effect = exception.ShareMountError( + share_id=share_info[0].share_id, + server_id=instance.uuid, + reason="fake_reason", + ) + + self.assertRaises( + exception.InstanceNotRescuable, + self.compute.rescue_instance, + mock_context, + instance=instance, + rescue_password="password", + rescue_image_ref=image_ref, + clean_shutdown=True, + ) + + self.assertEqual(instance.vm_state, 'error') + self.compute.terminate_instance(ctxt, instance, []) + + @mock.patch('nova.compute.manager.ComputeManager._get_share_info') + @mock.patch.object(nova.compute.manager.ComputeManager, + '_get_instance_block_device_info') + @mock.patch.object(image_api.API, "get") + @mock.patch.object(fake.FakeDriver, 'power_off') + @mock.patch.object(nova.virt.fake.FakeDriver, "rescue") + def test_rescue_with_base_image_when_image_not_specified(self, + mock_rescue, mock_power_off, mock_image_get, mock_get_block_info, + mock_get_share_info): + image_ref = FAKE_IMAGE_REF + system_meta = {"image_base_image_ref": image_ref} + rescue_image_meta = {} + params = {"task_state": task_states.RESCUING, + "system_metadata": system_meta} + share_info = objects.ShareMappingList() + mock_get_share_info.return_value = share_info + + instance = self._create_fake_instance_obj(params=params) + + ctxt = context.get_admin_context() + mock_context = mock.Mock() + mock_context.elevated.return_value = ctxt + + mock_get_block_info.return_value = mock.sentinel.block_device_info + mock_image_get.return_value = rescue_image_meta + + share_info = objects.ShareMappingList() + mock_get_share_info.return_value = share_info + self.compute.rescue_instance(mock_context, instance=instance, rescue_password="password", rescue_image_ref=None, @@ -2636,7 +2746,8 @@ class ComputeTestCase(BaseTestCase, mock_rescue.assert_called_with(ctxt, instance, [], test.MatchType(objects.ImageMeta), 'password', - mock.sentinel.block_device_info) + mock.sentinel.block_device_info, + share_info) self.compute.terminate_instance(self.context, instance, []) def test_power_on(self): diff --git a/nova/tests/unit/compute/test_compute_mgr.py b/nova/tests/unit/compute/test_compute_mgr.py index 52a0a82ea3f5..ebe9f1cc10c7 100644 --- a/nova/tests/unit/compute/test_compute_mgr.py +++ b/nova/tests/unit/compute/test_compute_mgr.py @@ -5706,6 +5706,7 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase, fake_nw_info = network_model.NetworkInfo() rescue_image_meta = objects.ImageMeta.from_dict( {'id': uuids.image_id, 'name': uuids.image_name}) + with test.nested( mock.patch.object(self.context, 'elevated', return_value=self.context), @@ -5724,13 +5725,18 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase, mock.patch.object(compute_utils, 'notify_usage_exists'), mock.patch.object(self.compute, '_get_power_state', return_value=power_state.RUNNING), - mock.patch.object(instance, 'save') + mock.patch.object(instance, 'save'), + mock.patch('nova.compute.manager.ComputeManager._get_share_info') ) as ( elevated_context, get_nw_info, get_rescue_image, get_bdm_list, get_block_info, notify_instance_usage, power_off_instance, driver_rescue, notify_usage_exists, - get_power_state, instance_save + get_power_state, instance_save, mock_get_share_info ): + + share_info = objects.ShareMappingList() + mock_get_share_info.return_value = share_info + self.compute.rescue_instance( self.context, instance, rescue_password='verybadpass', rescue_image_ref=None, clean_shutdown=clean_shutdown) @@ -5765,7 +5771,7 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase, driver_rescue.assert_called_once_with( self.context, instance, fake_nw_info, rescue_image_meta, - 'verybadpass', mock.sentinel.block_device_info) + 'verybadpass', mock.sentinel.block_device_info, share_info) notify_usage_exists.assert_called_once_with(self.compute.notifier, self.context, instance, 'fake-mini', current_period=True) diff --git a/nova/tests/unit/virt/ironic/test_driver.py b/nova/tests/unit/virt/ironic/test_driver.py index 95ee0c00808f..d28b4c9b1f66 100644 --- a/nova/tests/unit/virt/ironic/test_driver.py +++ b/nova/tests/unit/virt/ironic/test_driver.py @@ -2645,9 +2645,11 @@ class IronicDriverSyncTestCase(IronicDriverTestCase): fake_looping_call = FakeLoopingCall() mock_looping.return_value = fake_looping_call + share_info = objects.ShareMappingList() instance = fake_instance.fake_instance_obj(self.ctx, node=node.id) - self.driver.rescue(self.ctx, instance, None, None, 'xyz', None) + self.driver.rescue(self.ctx, instance, None, None, 'xyz', None, + share_info) self.mock_conn.set_node_provision_state.assert_called_once_with( node.id, 'rescue', rescue_password='xyz', ) @@ -2660,12 +2662,13 @@ class IronicDriverSyncTestCase(IronicDriverTestCase): mock_looping.return_value = fake_looping_call self.mock_conn.set_node_provision_state.side_effect = \ sdk_exc.BadRequestException() + share_info = objects.ShareMappingList() instance = fake_instance.fake_instance_obj(self.ctx, node=node.id) self.assertRaises( exception.InstanceRescueFailure, self.driver.rescue, - self.ctx, instance, None, None, 'xyz', None, + self.ctx, instance, None, None, 'xyz', None, share_info ) self.mock_conn.set_node_provision_state.assert_called_once_with( node.id, 'rescue', rescue_password='xyz', @@ -2680,11 +2683,12 @@ class IronicDriverSyncTestCase(IronicDriverTestCase): fake_validate.side_effect = exception.InstanceNotFound( instance_id='fake', ) + share_info = objects.ShareMappingList() self.assertRaises( exception.InstanceRescueFailure, self.driver.rescue, - self.ctx, instance, None, None, 'xyz', None, + self.ctx, instance, None, None, 'xyz', None, share_info ) @mock.patch.object(ironic_driver.IronicDriver, @@ -2695,12 +2699,13 @@ class IronicDriverSyncTestCase(IronicDriverTestCase): last_error='rescue failed') fake_validate.return_value = node + share_info = objects.ShareMappingList() instance = fake_instance.fake_instance_obj(self.ctx, node=node.id) self.assertRaises( exception.InstanceRescueFailure, self.driver.rescue, - self.ctx, instance, None, None, 'xyz', None, + self.ctx, instance, None, None, 'xyz', None, share_info ) @mock.patch.object(loopingcall, 'FixedIntervalLoopingCall') diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index f7463e2a335c..3fe5dae5842f 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -26217,7 +26217,7 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin): self, instance, mock_instance_metadata, mock_supports_direct_io, mock_build_device_metadata, mock_set_host_enabled, mock_get_mdev, mock_get_image_meta_by_ref, image_meta_dict=None, exists=None, - instance_image_meta_dict=None, block_device_info=None, + instance_image_meta_dict=None, block_device_info=None, share_info=None ): self.flags(instances_path=self.useFixture(fixtures.TempDir()).path) @@ -26256,9 +26256,11 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin): mock.patch.object(self.drvr, '_connect_volume'), ) as (mock_create_guest, mock_connect_volume): + share_info = objects.ShareMappingList() + self.drvr.rescue(self.context, instance, network_info, image_meta, rescue_password, - block_device_info) + block_device_info, share_info) self.assertTrue(mock_create_guest.called) @@ -26388,9 +26390,10 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin): # Assert that InstanceNotRescuable is raised for lxc virt_type self.flags(virt_type='lxc', group='libvirt') + share_info = objects.ShareMappingList() self.assertRaises(exception.InstanceNotRescuable, self.drvr.rescue, self.context, instance, network_info, - rescue_image_meta, None, None) + rescue_image_meta, None, None, share_info) def test_rescue_stable_device(self): # Assert the imagebackend behaviour and domain device layout @@ -26462,12 +26465,15 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin): 'block_device_mapping': bdms} bdm = block_device_info['block_device_mapping'][0] bdm['connection_info'] = conn_info + share_info = objects.ShareMappingList() backend, domain = self._test_rescue( - instance, - image_meta_dict=rescue_image_meta_dict, - instance_image_meta_dict=inst_image_meta_dict, - block_device_info=block_device_info) + instance, + image_meta_dict=rescue_image_meta_dict, + instance_image_meta_dict=inst_image_meta_dict, + block_device_info=block_device_info, + share_info=share_info, + ) # Assert that we created the expected set of disks, and no others self.assertEqual(['disk.rescue', 'kernel.rescue', 'ramdisk.rescue'], @@ -26536,16 +26542,18 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin): ) as ( mock_create, mock_destroy, mock_get_guest_xml, mock_create_image, mock_get_existing_xml, mock_inst_path, mock_get_disk_info, - mock_image_get, mock_from_dict, mock_open, + mock_image_get, mock_from_dict, mock_open ): self.flags(virt_type='kvm', group='libvirt') mock_image_get.return_value = mock.sentinel.bdm_image_meta_dict mock_from_dict.return_value = mock.sentinel.bdm_image_meta mock_get_disk_info.return_value = disk_info + share_info = nova.objects.share_mapping.ShareMappingList() + drvr.rescue(self.context, instance, network_info, rescue_image_meta, mock.sentinel.rescue_password, - block_device_info) + block_device_info, share_info=share_info) # Assert that we fetch image metadata from Glance using the image # uuid stashed in the BDM and build an image_meta object using the @@ -26565,7 +26573,7 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin): mock_get_guest_xml.assert_called_once_with( self.context, instance, network_info, disk_info, mock.sentinel.bdm_image_meta, rescue=mock.ANY, mdevs=mock.ANY, - block_device_info=block_device_info) + block_device_info=block_device_info, share_info=share_info) def test_rescue_stable_device_bfv(self): """Assert the disk layout when rescuing BFV instances""" diff --git a/nova/tests/unit/virt/test_virt_drivers.py b/nova/tests/unit/virt/test_virt_drivers.py index 3370c4841f9c..b724130a2c45 100644 --- a/nova/tests/unit/virt/test_virt_drivers.py +++ b/nova/tests/unit/virt/test_virt_drivers.py @@ -284,8 +284,9 @@ class _VirtDriverTestCase(_FakeDriverBackendTestCase): def test_rescue(self): image_meta = objects.ImageMeta.from_dict({}) instance_ref, network_info = self._get_running_instance() + share_info = objects.ShareMappingList() self.connection.rescue(self.ctxt, instance_ref, network_info, - image_meta, '', None) + image_meta, '', None, share_info) @catch_notimplementederror def test_unrescue_unrescued_instance(self): @@ -297,8 +298,9 @@ class _VirtDriverTestCase(_FakeDriverBackendTestCase): def test_unrescue_rescued_instance(self, mock_unlink): image_meta = objects.ImageMeta.from_dict({}) instance_ref, network_info = self._get_running_instance() + share_info = objects.ShareMappingList() self.connection.rescue(self.ctxt, instance_ref, network_info, - image_meta, '', None) + image_meta, '', None, share_info) self.connection.unrescue(self.ctxt, instance_ref) @catch_notimplementederror diff --git a/nova/virt/driver.py b/nova/virt/driver.py index f90c1b58b3be..a268d435d114 100644 --- a/nova/virt/driver.py +++ b/nova/virt/driver.py @@ -1016,7 +1016,7 @@ class ComputeDriver(object): raise NotImplementedError() def rescue(self, context, instance, network_info, image_meta, - rescue_password, block_device_info): + rescue_password, block_device_info, share_info): """Rescue the specified instance. :param nova.context.RequestContext context: @@ -1030,6 +1030,8 @@ class ComputeDriver(object): :param rescue_password: new root password to set for rescue. :param dict block_device_info: The block device mapping of the instance. + :param nova.objects.share_mapping.ShareMapingList share_info + list of share_mapping """ raise NotImplementedError() diff --git a/nova/virt/fake.py b/nova/virt/fake.py index aadf2b97d325..3cc8e926078f 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -245,7 +245,7 @@ class FakeDriver(driver.ComputeDriver): pass def rescue(self, context, instance, network_info, image_meta, - rescue_password, block_device_info): + rescue_password, block_device_info, share_info): pass def unrescue( diff --git a/nova/virt/ironic/driver.py b/nova/virt/ironic/driver.py index 8a95f949373e..7cd01de49f39 100644 --- a/nova/virt/ironic/driver.py +++ b/nova/virt/ironic/driver.py @@ -2150,7 +2150,7 @@ class IronicDriver(virt_driver.ComputeDriver): raise exception.IronicAPIVersionNotAvailable(version=version) def rescue(self, context, instance, network_info, image_meta, - rescue_password, block_device_info): + rescue_password, block_device_info, share_info): """Rescue the specified instance. :param nova.context.RequestContext context: @@ -2165,6 +2165,8 @@ class IronicDriver(virt_driver.ComputeDriver): :param rescue_password: new root password to set for rescue. :param dict block_device_info: The block device mapping of the instance. + :param nova.objects.share_mapping.ShareMapingList share_info + optional list of share_mapping :raise InstanceRescueFailure if rescue fails. """ LOG.debug('Rescue called for instance', instance=instance) diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index 5b64404ff933..2ab419cdbe0a 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -4465,7 +4465,7 @@ class LibvirtDriver(driver.ComputeDriver): ) def rescue(self, context, instance, network_info, image_meta, - rescue_password, block_device_info): + rescue_password, block_device_info, share_info): """Loads a VM using rescue images. A rescue is normally performed when something goes wrong with the @@ -4496,9 +4496,13 @@ class LibvirtDriver(driver.ComputeDriver): :param rescue_password: new root password to set for rescue. :param dict block_device_info: The block device mapping of the instance. + :param nova.objects.ShareMappingList share_info: + list of share_mapping """ + instance_dir = libvirt_utils.get_instance_path(instance) - unrescue_xml = self._get_existing_domain_xml(instance, network_info) + unrescue_xml = self._get_existing_domain_xml( + instance, network_info, share_info=share_info) unrescue_xml_path = os.path.join(instance_dir, 'unrescue.xml') with open(unrescue_xml_path, 'w') as f: f.write(unrescue_xml) @@ -4584,7 +4588,8 @@ class LibvirtDriver(driver.ComputeDriver): xml = self._get_guest_xml(context, instance, network_info, disk_info, image_meta, rescue=rescue_images, mdevs=mdevs, - block_device_info=block_device_info) + block_device_info=block_device_info, + share_info=share_info) self._destroy(instance) self._create_guest( context, xml, instance, post_xml_callback=gen_confdrive, diff --git a/nova/virt/vmwareapi/driver.py b/nova/virt/vmwareapi/driver.py index 5988ce469f38..7ed562502039 100644 --- a/nova/virt/vmwareapi/driver.py +++ b/nova/virt/vmwareapi/driver.py @@ -656,7 +656,7 @@ class VMwareVCDriver(driver.ComputeDriver): self._vmops.resume(instance) def rescue(self, context, instance, network_info, image_meta, - rescue_password, block_device_info): + rescue_password, block_device_info, share_info): """Rescue the specified instance.""" self._vmops.rescue(context, instance, network_info, image_meta)