Merge "libvirt: Support boot from volume stable device instance rescue"
This commit is contained in:
commit
1d0f934cbb
|
@ -527,6 +527,7 @@ class ProviderUsageBaseTestCase(test.TestCase, InstanceHelperMixin):
|
|||
os_traits.COMPUTE_IMAGE_TYPE_ISO,
|
||||
os_traits.COMPUTE_IMAGE_TYPE_QCOW2,
|
||||
os_traits.COMPUTE_IMAGE_TYPE_RAW,
|
||||
os_traits.COMPUTE_RESCUE_BFV,
|
||||
]
|
||||
])
|
||||
|
||||
|
|
|
@ -22823,6 +22823,141 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
|
|||
query = "devices/disk[source/@file = '%s']/boot/@order" % disk_path
|
||||
self.assertEqual('1', domain.xpath(query)[0])
|
||||
|
||||
def test_supports_bfv_rescue_capability(self):
|
||||
"""Assert that the supports_bfv_rescue capability is set"""
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
|
||||
self.assertTrue(drvr.capabilities.get('supports_bfv_rescue'))
|
||||
|
||||
def test_rescue_stable_device_bfv_without_instance_image_ref(self):
|
||||
"""Assert that image_meta is fetched from the bdms for bfv instances"""
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
|
||||
|
||||
# Set instance.image_ref to None for this BFV instance
|
||||
instance = self._create_instance({'config_drive': str(True)})
|
||||
instance.image_ref = None
|
||||
|
||||
rescue_image_meta = objects.ImageMeta.from_dict(
|
||||
{'id': uuids.rescue_image_id,
|
||||
'name': 'rescue',
|
||||
'properties': {'hw_rescue_device': 'disk',
|
||||
'hw_rescue_bus': 'virtio'}})
|
||||
bdm = objects.BlockDeviceMapping(self.context,
|
||||
**fake_block_device.FakeDbBlockDeviceDict({
|
||||
'id': 1,
|
||||
'image_id': uuids.bdm_image_id,
|
||||
'source_type': 'image',
|
||||
'destination_type': 'volume',
|
||||
'device_name': '/dev/vda',
|
||||
'boot_index': 0}))
|
||||
bdms = driver_block_device.convert_images([bdm])
|
||||
block_device_info = {'root_device_name': '/dev/vda',
|
||||
'ephemerals': [],
|
||||
'swap': None,
|
||||
'block_device_mapping': bdms}
|
||||
network_info = _fake_network_info(self)
|
||||
disk_info = {'mapping': {}}
|
||||
|
||||
with test.nested(
|
||||
mock.patch.object(drvr, '_create_domain'),
|
||||
mock.patch.object(drvr, '_destroy'),
|
||||
mock.patch.object(drvr, '_get_guest_xml'),
|
||||
mock.patch.object(drvr, '_create_image'),
|
||||
mock.patch.object(drvr, '_get_existing_domain_xml'),
|
||||
mock.patch.object(libvirt_utils, 'write_to_file'),
|
||||
mock.patch.object(libvirt_utils, 'get_instance_path'),
|
||||
mock.patch('nova.virt.libvirt.blockinfo.get_disk_info'),
|
||||
mock.patch('nova.image.glance.API.get'),
|
||||
mock.patch('nova.objects.image_meta.ImageMeta.from_dict')
|
||||
) as (mock_create, mock_destroy, mock_get_guest_xml, mock_create_image,
|
||||
mock_get_existing_xml, mock_write, mock_inst_path,
|
||||
mock_get_disk_info, mock_image_get, mock_from_dict):
|
||||
|
||||
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
|
||||
|
||||
drvr.rescue(self.context, instance, network_info,
|
||||
rescue_image_meta, mock.sentinel.rescue_password,
|
||||
block_device_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
|
||||
# returned dict.
|
||||
mock_image_get.assert_called_once_with(
|
||||
self.context, uuids.bdm_image_id)
|
||||
mock_from_dict.assert_called_once_with(
|
||||
mock.sentinel.bdm_image_meta_dict)
|
||||
|
||||
# Assert that get_disk_info is then called using this object
|
||||
mock_get_disk_info.assert_called_once_with(
|
||||
'kvm', instance, mock.sentinel.bdm_image_meta, rescue=True,
|
||||
block_device_info=block_device_info,
|
||||
rescue_image_meta=rescue_image_meta)
|
||||
|
||||
# Assert that this object is also used when building guest XML
|
||||
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)
|
||||
|
||||
def test_rescue_stable_device_bfv(self):
|
||||
"""Assert the disk layout when rescuing BFV instances"""
|
||||
|
||||
# NOTE(lyarwood): instance.image_ref is left in place here to allow us
|
||||
# to reuse the _test_rescue test method as we only care about the
|
||||
# eventual disk layout and not how we get the image_meta in this test.
|
||||
instance = self._create_instance({'config_drive': str(True)})
|
||||
|
||||
# Set ephemeral_gb to 0 to avoid any disk.local disks for being used
|
||||
instance.ephemeral_gb = 0
|
||||
inst_image_meta_dict = {'id': uuids.image_id, 'name': 'fake'}
|
||||
rescue_image_meta_dict = {
|
||||
'id': uuids.rescue_image_id,
|
||||
'name': 'rescue',
|
||||
'properties': {'hw_rescue_device': 'disk',
|
||||
'hw_rescue_bus': 'virtio'}}
|
||||
conn_info = {
|
||||
'driver_volume_type': 'iscsi',
|
||||
'data': {'device_path': '/dev/sdb'}}
|
||||
bdm = objects.BlockDeviceMapping(
|
||||
self.context,
|
||||
**fake_block_device.FakeDbBlockDeviceDict({
|
||||
'id': 1,
|
||||
'source_type': 'volume',
|
||||
'destination_type': 'volume',
|
||||
'device_name': '/dev/vda'}))
|
||||
bdms = driver_block_device.convert_volumes([bdm])
|
||||
block_device_info = {'root_device_name': '/dev/vda',
|
||||
'ephemerals': [],
|
||||
'swap': None,
|
||||
'block_device_mapping': bdms}
|
||||
bdm = block_device_info['block_device_mapping'][0]
|
||||
bdm['connection_info'] = conn_info
|
||||
|
||||
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)
|
||||
|
||||
# Assert that we created the expected set of disks, and no others
|
||||
self.assertEqual(['disk.rescue', 'kernel.rescue', 'ramdisk.rescue'],
|
||||
sorted(backend.created_disks.keys()))
|
||||
|
||||
# Assert that the original disks are presented first with the rescue
|
||||
# disk attached as the final device in the domain.
|
||||
expected_disk_paths = [backend.disks['disk.config'].path,
|
||||
'/dev/sdb', backend.disks['disk.rescue'].path]
|
||||
query = 'devices/disk/source/@*[name()="file" or name()="dev"]'
|
||||
disk_paths = domain.xpath(query)
|
||||
self.assertEqual(expected_disk_paths, disk_paths)
|
||||
|
||||
# Assert that the disk.rescue device has a boot order of 1
|
||||
disk_path = backend.disks['disk.rescue'].path
|
||||
query = "devices/disk[source/@file = '%s']/boot/@order" % disk_path
|
||||
self.assertEqual('1', domain.xpath(query)[0])
|
||||
|
||||
@mock.patch.object(libvirt_utils, 'get_instance_path')
|
||||
@mock.patch.object(libvirt_utils, 'load_file')
|
||||
@mock.patch.object(host.Host, '_get_domain')
|
||||
|
|
|
@ -333,6 +333,7 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||
"supports_image_type_ploop": requires_ploop_image,
|
||||
"supports_pcpus": True,
|
||||
"supports_accelerators": True,
|
||||
"supports_bfv_rescue": True,
|
||||
}
|
||||
super(LibvirtDriver, self).__init__(virtapi)
|
||||
|
||||
|
@ -3482,7 +3483,14 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||
image_meta = objects.ImageMeta.from_image_ref(
|
||||
context, self._image_api, instance.image_ref)
|
||||
else:
|
||||
image_meta = objects.ImageMeta.from_dict({})
|
||||
# NOTE(lyarwood): If instance.image_ref isn't set attempt to
|
||||
# lookup the original image_meta from the bdms. This will
|
||||
# return an empty dict if no valid image_meta is found.
|
||||
image_meta_dict = utils.get_bdm_image_metadata(
|
||||
context, self._image_api, self._volume_api,
|
||||
block_device_info['block_device_mapping'],
|
||||
legacy_bdm=False)
|
||||
image_meta = objects.ImageMeta.from_dict(image_meta_dict)
|
||||
|
||||
else:
|
||||
LOG.info("Attempting an unstable device rescue", instance=instance)
|
||||
|
|
Loading…
Reference in New Issue