Merge "VMware: fix VM rescue problem with VNC console"
This commit is contained in:
commit
2235a36bcf
@ -41,7 +41,6 @@ from nova import block_device
|
||||
from nova.compute import api as compute_api
|
||||
from nova.compute import power_state
|
||||
from nova.compute import task_states
|
||||
from nova.compute import vm_states
|
||||
from nova import context
|
||||
from nova import exception
|
||||
from nova.image import glance
|
||||
@ -1441,34 +1440,6 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
|
||||
self.instance)
|
||||
self.assertFalse(mock_reboot.called)
|
||||
|
||||
def destroy_rescued(self, fake_method):
|
||||
self._rescue()
|
||||
with contextlib.nested(
|
||||
mock.patch.object(self.conn._volumeops, "detach_disk_from_vm",
|
||||
fake_method),
|
||||
mock.patch.object(vm_util, "power_on_instance"),
|
||||
) as (fake_detach, fake_power_on):
|
||||
self.instance['vm_state'] = vm_states.RESCUED
|
||||
self.conn.destroy(self.context, self.instance, self.network_info)
|
||||
inst_path = ds_util.DatastorePath(self.ds, self.uuid,
|
||||
'%s.vmdk' % self.uuid)
|
||||
self.assertFalse(vmwareapi_fake.get_file(str(inst_path)))
|
||||
rescue_file_path = ds_util.DatastorePath(
|
||||
self.ds, '%s-rescue' % self.uuid, '%s-rescue.vmdk' % self.uuid)
|
||||
self.assertFalse(vmwareapi_fake.get_file(str(rescue_file_path)))
|
||||
# Unrescue does not power on with destroy
|
||||
self.assertFalse(fake_power_on.called)
|
||||
|
||||
def test_destroy_rescued(self):
|
||||
def fake_detach_disk_from_vm(*args, **kwargs):
|
||||
pass
|
||||
self.destroy_rescued(fake_detach_disk_from_vm)
|
||||
|
||||
def test_destroy_rescued_with_exception(self):
|
||||
def fake_detach_disk_from_vm(*args, **kwargs):
|
||||
raise exception.NovaException('Here is my fake exception')
|
||||
self.destroy_rescued(fake_detach_disk_from_vm)
|
||||
|
||||
def test_destroy(self):
|
||||
self._create_vm()
|
||||
info = self._get_info()
|
||||
@ -1585,70 +1556,17 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
|
||||
|
||||
self.conn.rescue(self.context, self.instance, self.network_info,
|
||||
self.image, 'fake-password')
|
||||
info = self._get_info(name='1-rescue',
|
||||
uuid='%s-rescue' % self.uuid)
|
||||
info = self.conn.get_info({'name': '1',
|
||||
'uuid': self.uuid,
|
||||
'node': self.instance_node})
|
||||
self._check_vm_info(info, power_state.RUNNING)
|
||||
info = self._get_info()
|
||||
info = self.conn.get_info({'name': '1-orig',
|
||||
'uuid': '%s-orig' % self.uuid,
|
||||
'node': self.instance_node})
|
||||
self._check_vm_info(info, power_state.SHUTDOWN)
|
||||
self.assertIsNotNone(vm_util.vm_ref_cache_get('%s-rescue' % self.uuid))
|
||||
self.assertIsNotNone(vm_util.vm_ref_cache_get(self.uuid))
|
||||
self.assertEqual(1, self._power_on_called)
|
||||
|
||||
def test_rescue(self):
|
||||
self._rescue()
|
||||
inst_file_path = ds_util.DatastorePath(self.ds, self.uuid,
|
||||
'%s.vmdk' % self.uuid)
|
||||
self.assertTrue(vmwareapi_fake.get_file(str(inst_file_path)))
|
||||
rescue_file_path = ds_util.DatastorePath(self.ds,
|
||||
'%s-rescue' % self.uuid,
|
||||
'%s-rescue.vmdk' % self.uuid)
|
||||
self.assertTrue(vmwareapi_fake.get_file(str(rescue_file_path)))
|
||||
|
||||
def test_rescue_with_config_drive(self):
|
||||
self.flags(force_config_drive=True)
|
||||
self._rescue(config_drive=True)
|
||||
|
||||
def test_unrescue(self):
|
||||
# NOTE(dims): driver unrescue ends up eventually in vmops.unrescue
|
||||
# with power_on=True, the test_destroy_rescued tests the
|
||||
# vmops.unrescue with power_on=False
|
||||
self._rescue()
|
||||
vm_ref = vm_util.get_vm_ref(self.conn._session,
|
||||
self.instance)
|
||||
vm_rescue_ref = vm_util.get_vm_ref_from_name(self.conn._session,
|
||||
'%s-rescue' % self.uuid)
|
||||
|
||||
self.poweroff_instance = vm_util.power_off_instance
|
||||
|
||||
def fake_power_off_instance(session, instance, vm_ref):
|
||||
# This is called so that we actually poweroff the simulated vm.
|
||||
# The reason for this is that there is a validation in destroy
|
||||
# that the instance is not powered on.
|
||||
self.poweroff_instance(session, instance, vm_ref)
|
||||
|
||||
def fake_detach_disk_from_vm(vm_ref, instance,
|
||||
device_name, destroy_disk=False):
|
||||
self.test_device_name = device_name
|
||||
info = self.conn.get_info(instance)
|
||||
self._check_vm_info(info, power_state.SHUTDOWN)
|
||||
|
||||
with contextlib.nested(
|
||||
mock.patch.object(vm_util, "power_off_instance",
|
||||
side_effect=fake_power_off_instance),
|
||||
mock.patch.object(self.conn._volumeops, "detach_disk_from_vm",
|
||||
side_effect=fake_detach_disk_from_vm),
|
||||
mock.patch.object(vm_util, "power_on_instance"),
|
||||
) as (poweroff, detach, fake_power_on):
|
||||
self.conn.unrescue(self.instance, None)
|
||||
poweroff.assert_called_once_with(self.conn._session, mock.ANY,
|
||||
vm_rescue_ref)
|
||||
detach.assert_called_once_with(vm_rescue_ref, mock.ANY,
|
||||
self.test_device_name)
|
||||
fake_power_on.assert_called_once_with(self.conn._session,
|
||||
self.instance,
|
||||
vm_ref=vm_ref)
|
||||
self.test_vm_ref = None
|
||||
self.test_device_name = None
|
||||
|
||||
def test_get_diagnostics(self):
|
||||
self._create_vm()
|
||||
expected = {'memoryReservation': 0, 'suspendInterval': 0,
|
||||
|
@ -1199,6 +1199,49 @@ class VMwareVMUtilTestCase(test.NoDBTestCase):
|
||||
fake_devices)
|
||||
mock_reconfigure.assert_called_once_with(session, 'fake-ref', mock.ANY)
|
||||
|
||||
def test_get_vm_boot_spec(self):
|
||||
disk = fake.VirtualDisk()
|
||||
disk.key = 7
|
||||
fake_factory = fake.FakeFactory()
|
||||
result = vm_util.get_vm_boot_spec(fake_factory,
|
||||
disk)
|
||||
expected = fake_factory.create('ns0:VirtualMachineConfigSpec')
|
||||
boot_disk = fake_factory.create(
|
||||
'ns0:VirtualMachineBootOptionsBootableDiskDevice')
|
||||
boot_disk.deviceKey = disk.key
|
||||
boot_options = fake_factory.create('ns0:VirtualMachineBootOptions')
|
||||
boot_options.bootOrder = [boot_disk]
|
||||
expected.bootOptions = boot_options
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
def _get_devices(self, filename):
|
||||
devices = fake._create_array_of_type('VirtualDevice')
|
||||
devices.VirtualDevice = self._vmdk_path_and_adapter_type_devices(
|
||||
filename)
|
||||
return devices
|
||||
|
||||
def test_find_rescue_device(self):
|
||||
instance_uuid = uuidutils.generate_uuid()
|
||||
fake_instance = self.fake_instance_obj({'id': 7, 'name': 'fake!',
|
||||
'uuid': instance_uuid,
|
||||
'vcpus': 2, 'memory_mb': 2048})
|
||||
filename = '[test_datastore] uuid/uuid-rescue.vmdk'
|
||||
devices = self._get_devices(filename)
|
||||
device = vm_util.find_rescue_device(devices, fake_instance)
|
||||
self.assertEqual(filename, device.backing.fileName)
|
||||
|
||||
def test_find_rescue_device_not_found(self):
|
||||
instance_uuid = uuidutils.generate_uuid()
|
||||
fake_instance = self.fake_instance_obj({'id': 7, 'name': 'fake!',
|
||||
'uuid': instance_uuid,
|
||||
'vcpus': 2, 'memory_mb': 2048})
|
||||
filename = '[test_datastore] uuid/uuid.vmdk'
|
||||
devices = self._get_devices(filename)
|
||||
self.assertRaises(exception.NotFound,
|
||||
vm_util.find_rescue_device,
|
||||
devices,
|
||||
fake_instance)
|
||||
|
||||
|
||||
@mock.patch.object(driver.VMwareAPISession, 'vim', stubs.fake_vim_prop)
|
||||
class VMwareVMUtilGetHostRefTestCase(test.NoDBTestCase):
|
||||
|
@ -351,6 +351,67 @@ class VMwareVMOpsTestCase(test.NoDBTestCase):
|
||||
def test_get_datacenter_ref_and_name_with_no_datastore(self):
|
||||
self._test_get_datacenter_ref_and_name()
|
||||
|
||||
@mock.patch.object(vm_util, 'power_off_instance')
|
||||
@mock.patch.object(ds_util, 'disk_copy')
|
||||
@mock.patch.object(vm_util, 'get_vm_ref', return_value='fake-ref')
|
||||
@mock.patch.object(vm_util, 'get_values_from_object_properties')
|
||||
@mock.patch.object(vm_util, 'find_rescue_device')
|
||||
@mock.patch.object(vm_util, 'get_vm_boot_spec')
|
||||
@mock.patch.object(vm_util, 'reconfigure_vm')
|
||||
@mock.patch.object(vm_util, 'power_on_instance')
|
||||
@mock.patch.object(ds_util, 'get_datastore_by_ref')
|
||||
def test_rescue(self, mock_get_ds_by_ref, mock_power_on, mock_reconfigure,
|
||||
mock_get_boot_spec, mock_find_rescue,
|
||||
mock_get_values, mock_get_vm_ref, mock_disk_copy,
|
||||
mock_power_off):
|
||||
_volumeops = mock.Mock()
|
||||
self._vmops._volumeops = _volumeops
|
||||
|
||||
ds = ds_util.Datastore('fake-ref', 'ds1')
|
||||
mock_get_ds_by_ref.return_value = ds
|
||||
mock_find_rescue.return_value = 'fake-rescue-device'
|
||||
mock_get_boot_spec.return_value = 'fake-boot-spec'
|
||||
|
||||
device = vmwareapi_fake.DataObject()
|
||||
backing = vmwareapi_fake.DataObject()
|
||||
backing.datastore = ds.ref
|
||||
device.backing = backing
|
||||
vmdk = vm_util.VmdkInfo('[fake] uuid/root.vmdk',
|
||||
'fake-adapter',
|
||||
'fake-disk',
|
||||
'fake-capacity',
|
||||
device)
|
||||
|
||||
with contextlib.nested(
|
||||
mock.patch.object(self._vmops, 'get_datacenter_ref_and_name'),
|
||||
mock.patch.object(vm_util, 'get_vmdk_info',
|
||||
return_value=vmdk)
|
||||
) as (_get_dc_ref_and_name, fake_vmdk_info):
|
||||
dc_info = mock.Mock()
|
||||
_get_dc_ref_and_name.return_value = dc_info
|
||||
self._vmops.rescue(self._context, self._instance, None, None)
|
||||
|
||||
mock_power_off.assert_called_once_with(self._session,
|
||||
self._instance,
|
||||
'fake-ref')
|
||||
|
||||
uuid = self._instance.image_ref
|
||||
cache_path = ds.build_path('vmware_base', uuid, uuid + '.vmdk')
|
||||
rescue_path = ds.build_path('fake_uuid', uuid + '-rescue.vmdk')
|
||||
|
||||
mock_disk_copy.assert_called_once_with(self._session, dc_info.ref,
|
||||
cache_path, rescue_path)
|
||||
_volumeops.attach_disk_to_vm.assert_called_once_with('fake-ref',
|
||||
self._instance, mock.ANY, mock.ANY, rescue_path)
|
||||
mock_get_boot_spec.assert_called_once_with(mock.ANY,
|
||||
'fake-rescue-device')
|
||||
mock_reconfigure.assert_called_once_with(self._session,
|
||||
'fake-ref',
|
||||
'fake-boot-spec')
|
||||
mock_power_on.assert_called_once_with(self._session,
|
||||
self._instance,
|
||||
vm_ref='fake-ref')
|
||||
|
||||
def test_unrescue_power_on(self):
|
||||
self._test_unrescue(True)
|
||||
|
||||
@ -358,58 +419,38 @@ class VMwareVMOpsTestCase(test.NoDBTestCase):
|
||||
self._test_unrescue(False)
|
||||
|
||||
def _test_unrescue(self, power_on):
|
||||
self._vmops._volumeops = mock.Mock()
|
||||
vm_rescue_ref = mock.Mock()
|
||||
_volumeops = mock.Mock()
|
||||
self._vmops._volumeops = _volumeops
|
||||
vm_ref = mock.Mock()
|
||||
|
||||
args_list = [(vm_rescue_ref, 'VirtualMachine',
|
||||
'config.hardware.device')]
|
||||
|
||||
def fake_call_method(module, method, *args, **kwargs):
|
||||
expected_args = args_list.pop(0)
|
||||
expected_args = (vm_ref, 'VirtualMachine',
|
||||
'config.hardware.device')
|
||||
self.assertEqual('get_dynamic_property', method)
|
||||
self.assertEqual(expected_args, args)
|
||||
|
||||
vmdk = vm_util.VmdkInfo(mock.sentinel.PATH,
|
||||
mock.sentinel.ADAPTER_TYPE,
|
||||
mock.sentinel.DISK_TYPE,
|
||||
mock.sentinel.CAPACITY,
|
||||
mock.sentinel.DEVICE)
|
||||
with contextlib.nested(
|
||||
mock.patch.object(vm_util, 'get_vmdk_info',
|
||||
return_value=vmdk),
|
||||
mock.patch.object(vm_util, 'get_vmdk_volume_disk'),
|
||||
mock.patch.object(vm_util, 'power_on_instance'),
|
||||
mock.patch.object(vm_util, 'find_rescue_device'),
|
||||
mock.patch.object(vm_util, 'get_vm_ref', return_value=vm_ref),
|
||||
mock.patch.object(vm_util, 'get_vm_ref_from_name',
|
||||
return_value=vm_rescue_ref),
|
||||
mock.patch.object(self._session, '_call_method',
|
||||
fake_call_method),
|
||||
mock.patch.object(vm_util, 'power_off_instance'),
|
||||
mock.patch.object(self._vmops, '_destroy_instance'),
|
||||
) as (_get_vmdk_info, _get_vmdk_volume_disk,
|
||||
_power_on_instance, _get_vm_ref, _get_vm_ref_from_name,
|
||||
_call_method, _power_off, _destroy_instance):
|
||||
mock.patch.object(vm_util, 'power_off_instance')
|
||||
) as (_power_on_instance, _find_rescue, _get_vm_ref,
|
||||
_call_method, _power_off):
|
||||
self._vmops.unrescue(self._instance, power_on=power_on)
|
||||
|
||||
_get_vmdk_info.assert_called_once_with(self._session,
|
||||
vm_ref, 'fake_uuid')
|
||||
_get_vmdk_volume_disk.assert_called_once_with(
|
||||
None, path=mock.sentinel.PATH)
|
||||
if power_on:
|
||||
_power_on_instance.assert_called_once_with(self._session,
|
||||
self._instance,
|
||||
vm_ref=vm_ref)
|
||||
self._instance, vm_ref=vm_ref)
|
||||
else:
|
||||
self.assertFalse(_power_on_instance.called)
|
||||
_get_vm_ref.assert_called_once_with(self._session,
|
||||
self._instance)
|
||||
_get_vm_ref_from_name.assert_called_once_with(self._session,
|
||||
'fake_uuid-rescue')
|
||||
_power_off.assert_called_once_with(self._session, self._instance,
|
||||
vm_rescue_ref)
|
||||
_destroy_instance.assert_called_once_with(self._instance,
|
||||
instance_name='fake_uuid-rescue')
|
||||
vm_ref)
|
||||
_volumeops.detach_disk_from_vm.assert_called_once_with(
|
||||
vm_ref, self._instance, mock.ANY, destroy_disk=True)
|
||||
|
||||
def _test_finish_migration(self, power_on=True, resize_instance=False):
|
||||
with contextlib.nested(
|
||||
|
@ -239,6 +239,22 @@ def get_vm_create_spec(client_factory, instance, name, data_store_name,
|
||||
return config_spec
|
||||
|
||||
|
||||
def get_vm_boot_spec(client_factory, device):
|
||||
"""Returns updated boot settings for the instance.
|
||||
|
||||
The boot order for the instance will be changed to have the
|
||||
input device as the boot disk.
|
||||
"""
|
||||
config_spec = client_factory.create('ns0:VirtualMachineConfigSpec')
|
||||
boot_disk = client_factory.create(
|
||||
'ns0:VirtualMachineBootOptionsBootableDiskDevice')
|
||||
boot_disk.deviceKey = device.key
|
||||
boot_options = client_factory.create('ns0:VirtualMachineBootOptions')
|
||||
boot_options.bootOrder = [boot_disk]
|
||||
config_spec.bootOptions = boot_options
|
||||
return config_spec
|
||||
|
||||
|
||||
def get_vm_resize_spec(client_factory, vcpus, memory_mb, extra_specs):
|
||||
"""Provides updates for a VM spec."""
|
||||
resize_spec = client_factory.create('ns0:VirtualMachineConfigSpec')
|
||||
@ -1446,6 +1462,26 @@ def power_off_instance(session, instance, vm_ref=None):
|
||||
LOG.debug("VM already powered off", instance=instance)
|
||||
|
||||
|
||||
def find_rescue_device(hardware_devices, instance):
|
||||
"""Returns the rescue device.
|
||||
|
||||
The method will raise an exception if the rescue device does not
|
||||
exist. The resuce device has suffix '-rescue.vmdk'.
|
||||
:param hardware_devices: the hardware devices for the instance
|
||||
:param instance: nova.objects.instance.Instance object
|
||||
:return: the rescue disk device object
|
||||
"""
|
||||
for device in hardware_devices.VirtualDevice:
|
||||
if (device.__class__.__name__ == "VirtualDisk" and
|
||||
device.backing.__class__.__name__ ==
|
||||
'VirtualDiskFlatVer2BackingInfo' and
|
||||
device.backing.fileName.endswith('-rescue.vmdk')):
|
||||
return device
|
||||
|
||||
msg = _('Rescue device does not exist for instance %s') % instance.uuid
|
||||
raise exception.NotFound(msg)
|
||||
|
||||
|
||||
def get_ephemeral_name(id):
|
||||
return 'ephemeral_%d.vmdk' % id
|
||||
|
||||
|
@ -37,7 +37,6 @@ from nova.api.metadata import base as instance_metadata
|
||||
from nova import compute
|
||||
from nova.compute import power_state
|
||||
from nova.compute import task_states
|
||||
from nova.compute import vm_states
|
||||
from nova.console import type as ctype
|
||||
from nova import context as nova_context
|
||||
from nova import exception
|
||||
@ -163,8 +162,6 @@ class VMwareVMOps(object):
|
||||
self._datastore_regex = datastore_regex
|
||||
self._base_folder = self._get_base_folder()
|
||||
self._tmp_folder = 'vmware_temp'
|
||||
self._rescue_suffix = '-rescue'
|
||||
self._migrate_suffix = '-orig'
|
||||
self._datastore_dc_mapping = {}
|
||||
self._datastore_browser_mapping = {}
|
||||
self._imagecache = imagecache.ImageCacheManager(self._session,
|
||||
@ -968,16 +965,6 @@ class VMwareVMOps(object):
|
||||
|
||||
# If there is a rescue VM then we need to destroy that one too.
|
||||
LOG.debug("Destroying instance", instance=instance)
|
||||
if instance.vm_state == vm_states.RESCUED:
|
||||
LOG.debug("Rescue VM configured", instance=instance)
|
||||
try:
|
||||
self.unrescue(instance, power_on=False)
|
||||
LOG.debug("Rescue VM destroyed", instance=instance)
|
||||
except Exception:
|
||||
rescue_name = instance.uuid + self._rescue_suffix
|
||||
self._destroy_instance(instance,
|
||||
destroy_disks=destroy_disks,
|
||||
instance_name=rescue_name)
|
||||
self._destroy_instance(instance, destroy_disks=destroy_disks)
|
||||
LOG.debug("Instance destroyed", instance=instance)
|
||||
|
||||
@ -1027,50 +1014,72 @@ class VMwareVMOps(object):
|
||||
reason = _("instance is not in a suspended state")
|
||||
raise exception.InstanceResumeFailure(reason=reason)
|
||||
|
||||
def _get_rescue_device(self, instance, vm_ref):
|
||||
hardware_devices = self._session._call_method(vim_util,
|
||||
"get_dynamic_property", vm_ref,
|
||||
"VirtualMachine", "config.hardware.device")
|
||||
return vm_util.find_rescue_device(hardware_devices,
|
||||
instance)
|
||||
|
||||
def rescue(self, context, instance, network_info, image_meta):
|
||||
"""Rescue the specified instance.
|
||||
|
||||
- shutdown the instance VM.
|
||||
- spawn a rescue VM (the vm name-label will be instance-N-rescue).
|
||||
|
||||
Attach the image that the instance was created from and boot from it.
|
||||
"""
|
||||
vm_ref = vm_util.get_vm_ref(self._session, instance)
|
||||
|
||||
vm_util.power_off_instance(self._session, instance, vm_ref)
|
||||
instance_name = instance.uuid + self._rescue_suffix
|
||||
self.spawn(context, instance, image_meta,
|
||||
None, None, network_info,
|
||||
instance_name=instance_name,
|
||||
power_on=False)
|
||||
# Get the root disk vmdk object
|
||||
vmdk = vm_util.get_vmdk_info(self._session, vm_ref,
|
||||
uuid=instance.uuid)
|
||||
ds_ref = vmdk.device.backing.datastore
|
||||
datastore = ds_util.get_datastore_by_ref(self._session, ds_ref)
|
||||
dc_info = self.get_datacenter_ref_and_name(datastore.ref)
|
||||
|
||||
# Attach vmdk to the rescue VM
|
||||
vmdk = vm_util.get_vmdk_info(self._session, vm_ref, instance.uuid)
|
||||
rescue_vm_ref = vm_util.get_vm_ref_from_name(self._session,
|
||||
instance_name)
|
||||
self._volumeops.attach_disk_to_vm(rescue_vm_ref,
|
||||
instance,
|
||||
vmdk.adapter_type,
|
||||
vmdk.disk_type,
|
||||
vmdk.path)
|
||||
vm_util.power_on_instance(self._session, instance,
|
||||
vm_ref=rescue_vm_ref)
|
||||
# Get the image details of the instance
|
||||
image_info = images.VMwareImage.from_image(instance.image_ref,
|
||||
image_meta)
|
||||
vi = VirtualMachineInstanceConfigInfo(instance,
|
||||
None,
|
||||
image_info,
|
||||
datastore,
|
||||
dc_info,
|
||||
self._imagecache)
|
||||
vm_util.power_off_instance(self._session, instance, vm_ref)
|
||||
|
||||
# Get the rescue disk path
|
||||
rescue_disk_path = datastore.build_path(instance.uuid,
|
||||
"%s-rescue.%s" % (image_info.image_id, image_info.file_type))
|
||||
|
||||
# Copy the cached image to the be the rescue disk. This will be used
|
||||
# as the rescue disk for the instance.
|
||||
ds_util.disk_copy(self._session, dc_info.ref,
|
||||
vi.cache_image_path, rescue_disk_path)
|
||||
# Attach the rescue disk to the instance
|
||||
self._volumeops.attach_disk_to_vm(vm_ref, instance, vmdk.adapter_type,
|
||||
vmdk.disk_type, rescue_disk_path)
|
||||
# Get the rescue device and configure the boot order to
|
||||
# boot from this device
|
||||
rescue_device = self._get_rescue_device(instance, vm_ref)
|
||||
factory = self._session.vim.client.factory
|
||||
boot_spec = vm_util.get_vm_boot_spec(factory, rescue_device)
|
||||
# Update the VM with the new boot order and power on
|
||||
vm_util.reconfigure_vm(self._session, vm_ref, boot_spec)
|
||||
vm_util.power_on_instance(self._session, instance, vm_ref=vm_ref)
|
||||
|
||||
def unrescue(self, instance, power_on=True):
|
||||
"""Unrescue the specified instance."""
|
||||
# Get the original vmdk_path
|
||||
|
||||
vm_ref = vm_util.get_vm_ref(self._session, instance)
|
||||
vmdk = vm_util.get_vmdk_info(self._session, vm_ref, instance.uuid)
|
||||
instance_name = instance.uuid + self._rescue_suffix
|
||||
# detach the original instance disk from the rescue disk
|
||||
vm_rescue_ref = vm_util.get_vm_ref_from_name(self._session,
|
||||
instance_name)
|
||||
hardware_devices = self._session._call_method(vim_util,
|
||||
"get_dynamic_property", vm_rescue_ref,
|
||||
"VirtualMachine", "config.hardware.device")
|
||||
device = vm_util.get_vmdk_volume_disk(hardware_devices, path=vmdk.path)
|
||||
vm_util.power_off_instance(self._session, instance, vm_rescue_ref)
|
||||
self._volumeops.detach_disk_from_vm(vm_rescue_ref, instance, device)
|
||||
self._destroy_instance(instance, instance_name=instance_name)
|
||||
# Get the rescue device and detach it from the instance.
|
||||
try:
|
||||
rescue_device = self._get_rescue_device(instance, vm_ref)
|
||||
except exception.NotFound:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error(_LE('Unable to access the rescue disk'),
|
||||
instance=instance)
|
||||
vm_util.power_off_instance(self._session, instance, vm_ref)
|
||||
self._volumeops.detach_disk_from_vm(vm_ref, instance, rescue_device,
|
||||
destroy_disk=True)
|
||||
if power_on:
|
||||
vm_util.power_on_instance(self._session, instance, vm_ref=vm_ref)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user