block_device: Add DriverImageBlockDevice to block_device_info

Change-Id: I17e0758e3b77caebd4d142664a8367ab4601ebdf
This commit is contained in:
Lee Yarwood 2022-01-26 17:51:27 +00:00 committed by melanie witt
parent 794d2f98d9
commit 5df97016b4
9 changed files with 241 additions and 83 deletions

View File

@ -71,6 +71,8 @@ called ``block_device_info``, and is generated by
``root_device_name`` ``root_device_name``
Hypervisor's notion of the root device's name Hypervisor's notion of the root device's name
``image``
An image backed disk if used
``ephemerals`` ``ephemerals``
A list of all ephemeral disks A list of all ephemeral disks
``block_device_mapping`` ``block_device_mapping``
@ -105,13 +107,6 @@ persist data to the BDM object in the DB.
In other contexts this filtering will not have happened, and In other contexts this filtering will not have happened, and
``block_device_mapping`` will contain all volumes. ``block_device_mapping`` will contain all volumes.
.. note::
Unlike BDMs, ``block_device_info`` does not currently represent all
disks that an instance might have. Significantly, it will not contain any
representation of an image-backed local disk, i.e. the root disk of a
typical instance which isn't boot-from-volume. Other representations used
by the libvirt driver explicitly reconstruct this missing disk.
libvirt driver specific BDM data structures libvirt driver specific BDM data structures
=========================================== ===========================================

View File

@ -2025,6 +2025,7 @@ class ComputeManager(manager.Manager):
ephemerals = [] ephemerals = []
swap = [] swap = []
block_device_mapping = [] block_device_mapping = []
image = []
for device in block_devices: for device in block_devices:
if block_device.new_format_is_ephemeral(device): if block_device.new_format_is_ephemeral(device):
@ -2036,8 +2037,12 @@ class ComputeManager(manager.Manager):
if driver_block_device.is_block_device_mapping(device): if driver_block_device.is_block_device_mapping(device):
block_device_mapping.append(device) block_device_mapping.append(device)
if driver_block_device.is_local_image(device):
image.append(device)
self._default_device_names_for_instance(instance, self._default_device_names_for_instance(instance,
root_device_name, root_device_name,
image,
ephemerals, ephemerals,
swap, swap,
block_device_mapping) block_device_mapping)

View File

@ -1389,13 +1389,14 @@ class ComputeVolumeTestCase(BaseTestCase):
@mock.patch.object(nova.virt.block_device, 'convert_snapshots') @mock.patch.object(nova.virt.block_device, 'convert_snapshots')
@mock.patch.object(nova.virt.block_device, 'convert_volumes') @mock.patch.object(nova.virt.block_device, 'convert_volumes')
@mock.patch.object(nova.virt.block_device, 'convert_ephemerals') @mock.patch.object(nova.virt.block_device, 'convert_ephemerals')
@mock.patch.object(nova.virt.block_device, 'convert_local_images')
@mock.patch.object(nova.virt.block_device, 'convert_swap') @mock.patch.object(nova.virt.block_device, 'convert_swap')
@mock.patch.object(nova.virt.block_device, 'attach_block_devices') @mock.patch.object(nova.virt.block_device, 'attach_block_devices')
def test_prep_block_device_with_blanks(self, attach_block_devices, def test_prep_block_device_with_blanks(self, attach_block_devices,
convert_swap, convert_ephemerals, convert_swap, convert_local_images,
convert_volumes, convert_snapshots, convert_ephemerals, convert_volumes,
convert_images, convert_blanks, convert_snapshots, convert_images,
get_swap): convert_blanks, get_swap):
instance = self._create_fake_instance_obj() instance = self._create_fake_instance_obj()
instance['root_device_name'] = '/dev/vda' instance['root_device_name'] = '/dev/vda'
root_volume = objects.BlockDeviceMapping( root_volume = objects.BlockDeviceMapping(
@ -1426,6 +1427,7 @@ class ComputeVolumeTestCase(BaseTestCase):
return bdm return bdm
convert_swap.return_value = [] convert_swap.return_value = []
convert_local_images.return_value = []
convert_ephemerals.return_value = [] convert_ephemerals.return_value = []
convert_volumes.return_value = [blank_volume1, blank_volume2] convert_volumes.return_value = [blank_volume1, blank_volume2]
convert_snapshots.return_value = [] convert_snapshots.return_value = []
@ -1438,6 +1440,7 @@ class ComputeVolumeTestCase(BaseTestCase):
'root_device_name': '/dev/vda', 'root_device_name': '/dev/vda',
'swap': [], 'swap': [],
'ephemerals': [], 'ephemerals': [],
'image': [],
'block_device_mapping': bdms 'block_device_mapping': bdms
} }
@ -1452,6 +1455,7 @@ class ComputeVolumeTestCase(BaseTestCase):
self.assertIsNotNone(bdm.device_name) self.assertIsNotNone(bdm.device_name)
convert_swap.assert_called_once_with(bdms) convert_swap.assert_called_once_with(bdms)
convert_local_images.assert_called_once_with(bdms)
convert_ephemerals.assert_called_once_with(bdms) convert_ephemerals.assert_called_once_with(bdms)
bdm_args = tuple(bdms) bdm_args = tuple(bdms)
convert_volumes.assert_called_once_with(bdm_args) convert_volumes.assert_called_once_with(bdm_args)
@ -3212,6 +3216,7 @@ class ComputeTestCase(BaseTestCase,
expected = { expected = {
'swap': None, 'swap': None,
'ephemerals': [], 'ephemerals': [],
'image': [],
'root_device_name': None, 'root_device_name': None,
'block_device_mapping': driver_bdms 'block_device_mapping': driver_bdms
} }
@ -3240,6 +3245,7 @@ class ComputeTestCase(BaseTestCase,
expected = { expected = {
'swap': None, 'swap': None,
'ephemerals': [], 'ephemerals': [],
'image': [],
'root_device_name': None, 'root_device_name': None,
'block_device_mapping': driver_bdms 'block_device_mapping': driver_bdms
} }
@ -3318,6 +3324,7 @@ class ComputeTestCase(BaseTestCase,
'size': 2 'size': 2
} }
], ],
'image': [],
'block_device_mapping': [], 'block_device_mapping': [],
'root_device_name': None 'root_device_name': None
} }
@ -6108,7 +6115,7 @@ class ComputeTestCase(BaseTestCase,
mock_pre.assert_called_once_with( mock_pre.assert_called_once_with(
test.MatchType(nova.context.RequestContext), test.MatchType(nova.context.RequestContext),
test.MatchType(objects.Instance), test.MatchType(objects.Instance),
{'swap': None, 'ephemerals': [], {'swap': None, 'ephemerals': [], 'image': [],
'root_device_name': None, 'root_device_name': None,
'block_device_mapping': []}, 'block_device_mapping': []},
mock.ANY, mock.ANY, mock.ANY) mock.ANY, mock.ANY, mock.ANY)
@ -6474,7 +6481,7 @@ class ComputeTestCase(BaseTestCase,
self.assertEqual(2, mock_notify.call_count) self.assertEqual(2, mock_notify.call_count)
post_live_migration.assert_has_calls([ post_live_migration.assert_has_calls([
mock.call(c, instance, {'swap': None, 'ephemerals': [], mock.call(c, instance, {'swap': None, 'ephemerals': [],
'root_device_name': None, 'image': [], 'root_device_name': None,
'block_device_mapping': []}, 'block_device_mapping': []},
migrate_data)]) migrate_data)])
migrate_instance_start.assert_has_calls([ migrate_instance_start.assert_has_calls([
@ -6705,7 +6712,7 @@ class ComputeTestCase(BaseTestCase,
mock_setup.assert_called_once_with(c, instance, self.compute.host, mock_setup.assert_called_once_with(c, instance, self.compute.host,
teardown=True) teardown=True)
mock_rollback.assert_called_once_with(c, instance, [], mock_rollback.assert_called_once_with(c, instance, [],
{'swap': None, 'ephemerals': [], {'swap': None, 'ephemerals': [], 'image': [],
'root_device_name': None, 'root_device_name': None,
'block_device_mapping': []}, 'block_device_mapping': []},
destroy_disks=True, migrate_data=None) destroy_disks=True, migrate_data=None)
@ -8134,7 +8141,7 @@ class ComputeTestCase(BaseTestCase,
self.compute._default_block_device_names(instance, {}, bdms) self.compute._default_block_device_names(instance, {}, bdms)
self.assertEqual('/dev/vda', instance.root_device_name) self.assertEqual('/dev/vda', instance.root_device_name)
mock_def.assert_called_once_with(instance, '/dev/vda', [], [], mock_def.assert_called_once_with(instance, '/dev/vda', [], [], [],
[bdm for bdm in bdms]) [bdm for bdm in bdms])
@mock.patch.object(objects.BlockDeviceMapping, 'save') @mock.patch.object(objects.BlockDeviceMapping, 'save')
@ -8148,7 +8155,7 @@ class ComputeTestCase(BaseTestCase,
self.compute._default_block_device_names(instance, {}, bdms) self.compute._default_block_device_names(instance, {}, bdms)
mock_def.assert_called_once_with(instance, '/dev/vda', [], [], mock_def.assert_called_once_with(instance, '/dev/vda', [], [], [],
[bdm for bdm in bdms]) [bdm for bdm in bdms])
@mock.patch.object(objects.Instance, 'save') @mock.patch.object(objects.Instance, 'save')
@ -8170,7 +8177,7 @@ class ComputeTestCase(BaseTestCase,
self.assertEqual('/dev/vda', instance.root_device_name) self.assertEqual('/dev/vda', instance.root_device_name)
mock_default_dev.assert_called_once_with(instance, mock.ANY, bdms[0]) mock_default_dev.assert_called_once_with(instance, mock.ANY, bdms[0])
mock_default_name.assert_called_once_with(instance, '/dev/vda', [], [], mock_default_name.assert_called_once_with(instance, '/dev/vda', [], [],
[bdm for bdm in bdms]) [], [bdm for bdm in bdms])
def test_default_block_device_names_with_blank_volumes(self): def test_default_block_device_names_with_blank_volumes(self):
instance = self._create_fake_instance_obj() instance = self._create_fake_instance_obj()
@ -8230,7 +8237,7 @@ class ComputeTestCase(BaseTestCase,
self.assertEqual('/dev/vda', instance.root_device_name) self.assertEqual('/dev/vda', instance.root_device_name)
self.assertTrue(object_save.called) self.assertTrue(object_save.called)
default_device_names.assert_called_once_with(instance, default_device_names.assert_called_once_with(instance,
'/dev/vda', [bdms[-2]], [bdms[-1]], '/dev/vda', [], [bdms[-2]], [bdms[-1]],
[bdm for bdm in bdms[:-2]]) [bdm for bdm in bdms[:-2]])
def test_reserve_block_device_name(self): def test_reserve_block_device_name(self):

View File

@ -74,6 +74,7 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
def _test_block_device_info(self, with_eph=True, with_swap=True, def _test_block_device_info(self, with_eph=True, with_swap=True,
with_bdms=True): with_bdms=True):
swap = {'device_name': '/dev/vdb', 'swap_size': 1} swap = {'device_name': '/dev/vdb', 'swap_size': 1}
image = [{'device_type': 'disk', 'boot_index': 0}]
ephemerals = [{'device_type': 'disk', 'guest_format': 'ext4', ephemerals = [{'device_type': 'disk', 'guest_format': 'ext4',
'device_name': '/dev/vdc1', 'size': 10}, 'device_name': '/dev/vdc1', 'size': 10},
{'disk_bus': 'ide', 'guest_format': None, {'disk_bus': 'ide', 'guest_format': None,
@ -84,6 +85,7 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
'device_path': 'fake_device'}] 'device_path': 'fake_device'}]
return {'root_device_name': '/dev/vda', return {'root_device_name': '/dev/vda',
'swap': swap if with_swap else {}, 'swap': swap if with_swap else {},
'image': image,
'ephemerals': ephemerals if with_eph else [], 'ephemerals': ephemerals if with_eph else [],
'block_device_mapping': 'block_device_mapping':
block_device_mapping if with_bdms else []} block_device_mapping if with_bdms else []}
@ -178,11 +180,16 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
instance_ref = objects.Instance(**self.test_instance) instance_ref = objects.Instance(**self.test_instance)
image_meta = objects.ImageMeta.from_dict(self.test_image_meta) image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
block_device_info = {
'image': [
{'device_type': 'disk', 'boot_index': 0},
]
}
with mock.patch.object(instance_ref, 'get_flavor', with mock.patch.object(instance_ref, 'get_flavor',
return_value=instance_ref.flavor) as get_flavor: return_value=instance_ref.flavor) as get_flavor:
mapping = blockinfo.get_disk_mapping("kvm", instance_ref, mapping = blockinfo.get_disk_mapping(
"virtio", "ide", "kvm", instance_ref, "virtio", "ide", image_meta,
image_meta) block_device_info=block_device_info)
# Since there was no block_device_info passed to get_disk_mapping we # Since there was no block_device_info passed to get_disk_mapping we
# expect to get the swap info from the flavor in the instance. # expect to get the swap info from the flavor in the instance.
get_flavor.assert_called_once_with() get_flavor.assert_called_once_with()
@ -202,7 +209,8 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
instance_ref = objects.Instance(**self.test_instance) instance_ref = objects.Instance(**self.test_instance)
image_meta = objects.ImageMeta.from_dict(self.test_image_meta) image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
block_device_info = { block_device_info = {
'root_device_name': '/dev/sda' 'root_device_name': '/dev/sda',
'image': [{'device_type': 'disk', 'boot_index': 0}],
} }
mapping = blockinfo.get_disk_mapping("kvm", instance_ref, mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
@ -490,9 +498,12 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
instance_ref = objects.Instance(**self.test_instance) instance_ref = objects.Instance(**self.test_instance)
image_meta = objects.ImageMeta.from_dict(self.test_image_meta) image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
mapping = blockinfo.get_disk_mapping("lxc", instance_ref, block_device_info = {
"lxc", "lxc", 'image': [{'device_type': 'disk', 'boot_index': 0}],
image_meta) }
mapping = blockinfo.get_disk_mapping(
"lxc", instance_ref, "lxc", "lxc", image_meta,
block_device_info=block_device_info)
expect = { expect = {
'disk': {'bus': 'lxc', 'dev': None, 'disk': {'bus': 'lxc', 'dev': None,
'type': 'disk', 'boot_index': '1'}, 'type': 'disk', 'boot_index': '1'},
@ -527,9 +538,14 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
instance_ref.flavor.swap = 5 instance_ref.flavor.swap = 5
image_meta = objects.ImageMeta.from_dict(self.test_image_meta) image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
mapping = blockinfo.get_disk_mapping("kvm", instance_ref, block_device_info = {
"virtio", "ide", 'image': [
image_meta) {'device_type': 'disk', 'boot_index': 0},
]
}
mapping = blockinfo.get_disk_mapping(
"kvm", instance_ref, "virtio", "ide", image_meta,
block_device_info=block_device_info)
expect = { expect = {
'disk': {'bus': 'virtio', 'dev': 'vda', 'disk': {'bus': 'virtio', 'dev': 'vda',
@ -549,6 +565,7 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
instance_ref.ephemeral_gb = 0 instance_ref.ephemeral_gb = 0
block_dev_info = {'swap': None, 'root_device_name': u'/dev/vda', block_dev_info = {'swap': None, 'root_device_name': u'/dev/vda',
'image': [],
'ephemerals': [], 'ephemerals': [],
'block_device_mapping': [{'boot_index': None, 'block_device_mapping': [{'boot_index': None,
'mount_device': u'/dev/vdb', 'mount_device': u'/dev/vdb',
@ -591,8 +608,14 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
instance_ref = objects.Instance(**self.test_instance) instance_ref = objects.Instance(**self.test_instance)
image_meta = objects.ImageMeta.from_dict(self.test_image_meta) image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
block_device_info = {
'image': [
{'device_type': 'disk', 'boot_index': 0},
]
}
mapping = blockinfo.get_disk_mapping( mapping = blockinfo.get_disk_mapping(
"kvm", instance_ref, "virtio", "ide", image_meta) "kvm", instance_ref, "virtio", "ide", image_meta,
block_device_info=block_device_info)
# Pick the first drive letter on the bus that is available # Pick the first drive letter on the bus that is available
# as the config drive. Delete the last device hardcode as # as the config drive. Delete the last device hardcode as
@ -647,8 +670,14 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
instance_ref = objects.Instance(**self.test_instance) instance_ref = objects.Instance(**self.test_instance)
image_meta = objects.ImageMeta.from_dict(self.test_image_meta) image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
block_device_info = {
'image': [
{'device_type': 'disk', 'boot_index': 0},
]
}
mapping = blockinfo.get_disk_mapping( mapping = blockinfo.get_disk_mapping(
"kvm", instance_ref, "virtio", "ide", image_meta) "kvm", instance_ref, "virtio", "ide", image_meta,
block_device_info=block_device_info)
expect = { expect = {
'disk': { 'disk': {
@ -697,9 +726,14 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
instance_ref = objects.Instance(**self.test_instance) instance_ref = objects.Instance(**self.test_instance)
image_meta = objects.ImageMeta.from_dict(self.test_image_meta) image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
mapping = blockinfo.get_disk_mapping("kvm", instance_ref, block_device_info = {
"virtio", "ide", 'image': [
image_meta) {'device_type': 'disk', 'boot_index': 0},
]
}
mapping = blockinfo.get_disk_mapping(
"kvm", instance_ref, "virtio", "ide", image_meta,
block_device_info=block_device_info)
expect = { expect = {
'disk': {'bus': 'virtio', 'dev': 'vda', 'disk': {'bus': 'virtio', 'dev': 'vda',
@ -718,6 +752,9 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
image_meta = objects.ImageMeta.from_dict(self.test_image_meta) image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
block_device_info = { block_device_info = {
'image': [
{'device_type': 'disk', 'boot_index': 0},
],
'ephemerals': [ 'ephemerals': [
{'device_type': 'disk', 'guest_format': 'ext4', {'device_type': 'disk', 'guest_format': 'ext4',
'device_name': '/dev/vdb', 'size': 10}, 'device_name': '/dev/vdb', 'size': 10},
@ -754,6 +791,8 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
block_device_info = { block_device_info = {
'swap': {'device_name': '/dev/vdb', 'swap': {'device_name': '/dev/vdb',
'swap_size': 10}, 'swap_size': 10},
'image': [{'device_type': 'disk',
'boot_index': 0}],
} }
mapping = blockinfo.get_disk_mapping("kvm", instance_ref, mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
"virtio", "ide", "virtio", "ide",
@ -775,6 +814,7 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
image_meta = objects.ImageMeta.from_dict(self.test_image_meta) image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
block_device_info = { block_device_info = {
'image': [],
'block_device_mapping': [ 'block_device_mapping': [
{'connection_info': "fake", {'connection_info': "fake",
'mount_device': "/dev/vda", 'mount_device': "/dev/vda",
@ -803,6 +843,7 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
image_meta = {} image_meta = {}
block_device_info = { block_device_info = {
'image': [],
'block_device_mapping': [ 'block_device_mapping': [
{'connection_info': None, {'connection_info': None,
'mount_device': None, 'mount_device': None,
@ -858,6 +899,7 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
image_meta = objects.ImageMeta.from_dict(self.test_image_meta) image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
block_device_info = { block_device_info = {
'image': [],
'block_device_mapping': [ 'block_device_mapping': [
{'connection_info': "fake", {'connection_info': "fake",
'mount_device': "/dev/vda", 'mount_device': "/dev/vda",
@ -899,6 +941,7 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
'root_device_name': '/dev/vdf', 'root_device_name': '/dev/vdf',
'swap': {'device_name': '/dev/vdy', 'swap': {'device_name': '/dev/vdy',
'swap_size': 10}, 'swap_size': 10},
'image': [{'device_type': 'disk', 'boot_index': 0}],
'ephemerals': [ 'ephemerals': [
{'device_type': 'disk', 'guest_format': 'ext4', {'device_type': 'disk', 'guest_format': 'ext4',
'device_name': '/dev/vdb', 'size': 10}, 'device_name': '/dev/vdb', 'size': 10},
@ -940,6 +983,8 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
'swap': {'device_name': '/dev/vdb', 'swap': {'device_name': '/dev/vdb',
'device_type': 'really_lame_type', 'device_type': 'really_lame_type',
'swap_size': 10}, 'swap_size': 10},
'image': [{'device_name': '/dev/vda',
'device_type': 'disk'}],
'ephemerals': [{'disk_bus': 'no_such_bus', 'ephemerals': [{'disk_bus': 'no_such_bus',
'device_type': 'yeah_right', 'device_type': 'yeah_right',
'device_name': '/dev/vdc', 'size': 10}], 'device_name': '/dev/vdc', 'size': 10}],
@ -951,6 +996,8 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
} }
expected_swap = {'device_name': '/dev/vdb', 'disk_bus': 'virtio', expected_swap = {'device_name': '/dev/vdb', 'disk_bus': 'virtio',
'device_type': 'disk', 'swap_size': 10} 'device_type': 'disk', 'swap_size': 10}
expected_image = {'device_name': '/dev/vda', 'device_type': 'disk',
'disk_bus': 'virtio'}
expected_ephemeral = {'disk_bus': 'virtio', expected_ephemeral = {'disk_bus': 'virtio',
'device_type': 'disk', 'device_type': 'disk',
'device_name': '/dev/vdc', 'size': 10} 'device_name': '/dev/vdc', 'size': 10}
@ -970,6 +1017,7 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
self.assertFalse(get_flavor_mock.called) self.assertFalse(get_flavor_mock.called)
self.assertEqual(expected_swap, block_device_info['swap']) self.assertEqual(expected_swap, block_device_info['swap'])
self.assertEqual(expected_image, block_device_info['image'][0])
self.assertEqual(expected_ephemeral, self.assertEqual(expected_ephemeral,
block_device_info['ephemerals'][0]) block_device_info['ephemerals'][0])
self.assertEqual(expected_bdm, self.assertEqual(expected_bdm,
@ -1441,6 +1489,15 @@ class DefaultDeviceNamesTestCase(test.NoDBTestCase):
'destination_type': 'volume', 'destination_type': 'volume',
'boot_index': -1}))] 'boot_index': -1}))]
self.image = [
objects.BlockDeviceMapping(self.context,
**fake_block_device.FakeDbBlockDeviceDict(
{'id': 6, 'instance_uuid': uuids.instance,
'source_type': 'image',
'destination_type': 'local',
'device_type': 'disk',
'boot_index': 0}))]
def tearDown(self): def tearDown(self):
super(DefaultDeviceNamesTestCase, self).tearDown() super(DefaultDeviceNamesTestCase, self).tearDown()
for patcher in self.patchers: for patcher in self.patchers:
@ -1450,7 +1507,7 @@ class DefaultDeviceNamesTestCase(test.NoDBTestCase):
'nova.virt.libvirt.utils.get_arch', 'nova.virt.libvirt.utils.get_arch',
return_value=obj_fields.Architecture.X86_64) return_value=obj_fields.Architecture.X86_64)
def _test_default_device_names(self, eph, swap, bdm, mock_get_arch): def _test_default_device_names(self, eph, swap, bdm, mock_get_arch):
bdms = eph + swap + bdm bdms = self.image + eph + swap + bdm
bdi = driver.get_block_device_info(self.instance, bdms) bdi = driver.get_block_device_info(self.instance, bdms)
blockinfo.default_device_names(self.virt_type, blockinfo.default_device_names(self.virt_type,
self.context, self.context,

View File

@ -20410,7 +20410,7 @@ class LibvirtConnTestCase(test.NoDBTestCase,
**fake_block_device.FakeDbBlockDeviceDict( **fake_block_device.FakeDbBlockDeviceDict(
{'id': 0, {'id': 0,
'source_type': 'volume', 'destination_type': 'volume', 'source_type': 'volume', 'destination_type': 'volume',
'device_name': '/dev/sda'})) 'device_name': '/dev/sda', 'boot_index': 0}))
info = {'block_device_mapping': driver_block_device.convert_volumes( info = {'block_device_mapping': driver_block_device.convert_volumes(
[bdm])} [bdm])}
info['block_device_mapping'][0]['connection_info'] = conn_info info['block_device_mapping'][0]['connection_info'] = conn_info
@ -24941,7 +24941,8 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
'id': 1, 'id': 1,
'source_type': 'volume', 'source_type': 'volume',
'destination_type': 'volume', 'destination_type': 'volume',
'device_name': '/dev/vda'})) 'device_name': '/dev/vda',
'boot_index': 0}))
bdms = driver_block_device.convert_volumes([bdm]) bdms = driver_block_device.convert_volumes([bdm])
block_device_info = {'root_device_name': '/dev/vda', block_device_info = {'root_device_name': '/dev/vda',
'ephemerals': [], 'ephemerals': [],

View File

@ -49,7 +49,8 @@ class TestDriverBlockDevice(test.NoDBTestCase):
'volume': driver_block_device.DriverVolumeBlockDevice, 'volume': driver_block_device.DriverVolumeBlockDevice,
'volsnapshot': driver_block_device.DriverVolSnapshotBlockDevice, 'volsnapshot': driver_block_device.DriverVolSnapshotBlockDevice,
'volimage': driver_block_device.DriverVolImageBlockDevice, 'volimage': driver_block_device.DriverVolImageBlockDevice,
'volblank': driver_block_device.DriverVolBlankBlockDevice 'volblank': driver_block_device.DriverVolBlankBlockDevice,
'image': driver_block_device.DriverImageBlockDevice,
} }
swap_bdm_dict = block_device.BlockDeviceDict( swap_bdm_dict = block_device.BlockDeviceDict(
@ -210,6 +211,27 @@ class TestDriverBlockDevice(test.NoDBTestCase):
'boot_index': -1, 'boot_index': -1,
'volume_type': None} 'volume_type': None}
image_bdm_dict = block_device.BlockDeviceDict(
{'id': 7, 'instance_uuid': uuids.instance,
'device_name': '/dev/vda',
'source_type': 'image',
'destination_type': 'local',
'disk_bus': 'virtio',
'device_type': 'disk',
'guest_format': 'ext4',
'boot_index': 0,
'image_id': 'fake-image-id-1',
'volume_size': 5})
image_driver_bdm = {
'device_name': '/dev/vda',
'device_type': 'disk',
'guest_format': 'ext4',
'disk_bus': 'virtio',
'boot_index': 0,
'image_id': 'fake-image-id-1',
'size': 5}
def setUp(self): def setUp(self):
super(TestDriverBlockDevice, self).setUp() super(TestDriverBlockDevice, self).setUp()
self.volume_api = mock.MagicMock(autospec=cinder.API) self.volume_api = mock.MagicMock(autospec=cinder.API)
@ -219,6 +241,8 @@ class TestDriverBlockDevice(test.NoDBTestCase):
# create bdm objects for testing # create bdm objects for testing
self.swap_bdm = fake_block_device.fake_bdm_object( self.swap_bdm = fake_block_device.fake_bdm_object(
self.context, self.swap_bdm_dict) self.context, self.swap_bdm_dict)
self.image_bdm = fake_block_device.fake_bdm_object(
self.context, self.image_bdm_dict)
self.ephemeral_bdm = fake_block_device.fake_bdm_object( self.ephemeral_bdm = fake_block_device.fake_bdm_object(
self.context, self.ephemeral_bdm_dict) self.context, self.ephemeral_bdm_dict)
self.volume_bdm = fake_block_device.fake_bdm_object( self.volume_bdm = fake_block_device.fake_bdm_object(
@ -337,6 +361,10 @@ class TestDriverBlockDevice(test.NoDBTestCase):
if field == 'attachment_id': if field == 'attachment_id':
# Must set UUID values on UUID fields. # Must set UUID values on UUID fields.
fake_value = ATTACHMENT_ID fake_value = ATTACHMENT_ID
elif isinstance(test_bdm._bdm_obj.fields[fld],
fields.UUIDField):
# Generically handle other UUID fields.
fake_value = uuids.fake_value
else: else:
fake_value = 'fake_changed_value' fake_value = 'fake_changed_value'
test_bdm[field] = fake_value test_bdm[field] = fake_value
@ -377,6 +405,20 @@ class TestDriverBlockDevice(test.NoDBTestCase):
def test_driver_swap_default_size(self): def test_driver_swap_default_size(self):
self._test_driver_default_size('swap') self._test_driver_default_size('swap')
def test_driver_image_block_device(self):
self._test_driver_device("image")
def test_driver_image_default_size(self):
self._test_driver_default_size('image')
def test_driver_image_block_device_destination_not_local(self):
self._test_driver_device('image')
bdm = self.image_bdm_dict.copy()
bdm['destination_type'] = 'volume'
self.assertRaises(driver_block_device._InvalidType,
self.driver_classes['image'],
fake_block_device.fake_bdm_object(self.context, bdm))
def test_driver_ephemeral_block_device(self): def test_driver_ephemeral_block_device(self):
self._test_driver_device("ephemeral") self._test_driver_device("ephemeral")
@ -406,7 +448,7 @@ class TestDriverBlockDevice(test.NoDBTestCase):
self.assertEqual(test_bdm.volume_size, 3) self.assertEqual(test_bdm.volume_size, 3)
self.assertEqual('fake-snapshot-id-1', test_bdm.get('snapshot_id')) self.assertEqual('fake-snapshot-id-1', test_bdm.get('snapshot_id'))
def test_driver_image_block_device(self): def test_driver_volume_image_block_device(self):
self._test_driver_device('volimage') self._test_driver_device('volimage')
test_bdm = self.driver_classes['volimage']( test_bdm = self.driver_classes['volimage'](
@ -416,7 +458,7 @@ class TestDriverBlockDevice(test.NoDBTestCase):
self.assertEqual(test_bdm.volume_size, 1) self.assertEqual(test_bdm.volume_size, 1)
self.assertEqual('fake-image-id-1', test_bdm.get('image_id')) self.assertEqual('fake-image-id-1', test_bdm.get('image_id'))
def test_driver_image_block_device_destination_local(self): def test_driver_volume_image_block_device_destination_local(self):
self._test_driver_device('volimage') self._test_driver_device('volimage')
bdm = self.volimage_bdm_dict.copy() bdm = self.volimage_bdm_dict.copy()
bdm['destination_type'] = 'local' bdm['destination_type'] = 'local'
@ -1263,12 +1305,8 @@ class TestDriverBlockDevice(test.NoDBTestCase):
def test_is_implemented(self): def test_is_implemented(self):
for bdm in (self.volimage_bdm, self.volume_bdm, self.swap_bdm, for bdm in (self.volimage_bdm, self.volume_bdm, self.swap_bdm,
self.ephemeral_bdm, self.volsnapshot_bdm): self.ephemeral_bdm, self.volsnapshot_bdm, self.image_bdm):
self.assertTrue(driver_block_device.is_implemented(bdm)) self.assertTrue(driver_block_device.is_implemented(bdm))
local_image = self.volimage_bdm_dict.copy()
local_image['destination_type'] = 'local'
self.assertFalse(driver_block_device.is_implemented(
fake_block_device.fake_bdm_object(self.context, local_image)))
def test_is_block_device_mapping(self): def test_is_block_device_mapping(self):
test_swap = self.driver_classes['swap'](self.swap_bdm) test_swap = self.driver_classes['swap'](self.swap_bdm)

View File

@ -227,6 +227,36 @@ class DriverSwapBlockDevice(DriverBlockDevice):
}) })
class DriverImageBlockDevice(DriverBlockDevice):
_valid_source = 'image'
_proxy_as_attr_inherited = set(['image_id'])
_new_only_fields = set([
'disk_bus',
'device_type',
'guest_format',
'boot_index',
])
_fields = set([
'device_name',
'size']) | _new_only_fields
_legacy_fields = (
_fields - _new_only_fields | set(['num', 'virtual_name']))
def _transform(self):
if (not self._bdm_obj.get('source_type') == 'image' or
not self._bdm_obj.get('destination_type') == 'local'):
raise _InvalidType
self.update({
'device_name': self._bdm_obj.device_name,
'size': self._bdm_obj.volume_size or 0,
'disk_bus': self._bdm_obj.disk_bus,
'device_type': self._bdm_obj.device_type,
'guest_format': self._bdm_obj.guest_format,
'image_id': self._bdm_obj.image_id,
'boot_index': 0,
})
class DriverEphemeralBlockDevice(DriverBlockDevice): class DriverEphemeralBlockDevice(DriverBlockDevice):
_new_only_fields = set(['disk_bus', 'device_type', 'guest_format']) _new_only_fields = set(['disk_bus', 'device_type', 'guest_format'])
_fields = set(['device_name', 'size']) | _new_only_fields _fields = set(['device_name', 'size']) | _new_only_fields
@ -802,15 +832,15 @@ def _convert_block_devices(device_type, block_device_mapping):
convert_swap = functools.partial(_convert_block_devices, convert_swap = functools.partial(_convert_block_devices,
DriverSwapBlockDevice) DriverSwapBlockDevice)
convert_local_images = functools.partial(_convert_block_devices,
DriverImageBlockDevice)
convert_ephemerals = functools.partial(_convert_block_devices, convert_ephemerals = functools.partial(_convert_block_devices,
DriverEphemeralBlockDevice) DriverEphemeralBlockDevice)
convert_volumes = functools.partial(_convert_block_devices, convert_volumes = functools.partial(_convert_block_devices,
DriverVolumeBlockDevice) DriverVolumeBlockDevice)
convert_snapshots = functools.partial(_convert_block_devices, convert_snapshots = functools.partial(_convert_block_devices,
DriverVolSnapshotBlockDevice) DriverVolSnapshotBlockDevice)
@ -897,9 +927,15 @@ def get_swap(transformed_list):
return None return None
_IMPLEMENTED_CLASSES = (DriverSwapBlockDevice, DriverEphemeralBlockDevice, _IMPLEMENTED_CLASSES = (
DriverVolumeBlockDevice, DriverVolSnapshotBlockDevice, DriverSwapBlockDevice,
DriverVolImageBlockDevice, DriverVolBlankBlockDevice) DriverEphemeralBlockDevice,
DriverVolumeBlockDevice,
DriverVolSnapshotBlockDevice,
DriverVolImageBlockDevice,
DriverVolBlankBlockDevice,
DriverImageBlockDevice
)
def is_implemented(bdm): def is_implemented(bdm):
@ -912,6 +948,10 @@ def is_implemented(bdm):
return False return False
def is_local_image(bdm):
return bdm.source_type == 'image' and bdm.destination_type == 'local'
def is_block_device_mapping(bdm): def is_block_device_mapping(bdm):
return (bdm.source_type in ('image', 'volume', 'snapshot', 'blank') and return (bdm.source_type in ('image', 'volume', 'snapshot', 'blank') and
bdm.destination_type == 'volume' and bdm.destination_type == 'volume' and

View File

@ -44,6 +44,7 @@ def get_block_device_info(instance, block_device_mapping):
of a dict containing the following keys: of a dict containing the following keys:
- root_device_name: device name of the root disk - root_device_name: device name of the root disk
- image: An instance of DriverImageBlockDevice or None
- ephemerals: a (potentially empty) list of DriverEphemeralBlockDevice - ephemerals: a (potentially empty) list of DriverEphemeralBlockDevice
instances instances
- swap: An instance of DriverSwapBlockDevice or None - swap: An instance of DriverSwapBlockDevice or None
@ -54,6 +55,8 @@ def get_block_device_info(instance, block_device_mapping):
from nova.virt import block_device as virt_block_device from nova.virt import block_device as virt_block_device
return { return {
'root_device_name': instance.root_device_name, 'root_device_name': instance.root_device_name,
'image': virt_block_device.convert_local_images(
block_device_mapping),
'ephemerals': virt_block_device.convert_ephemerals( 'ephemerals': virt_block_device.convert_ephemerals(
block_device_mapping), block_device_mapping),
'block_device_mapping': 'block_device_mapping':
@ -79,6 +82,14 @@ def swap_is_usable(swap):
return swap and swap['device_name'] and swap['swap_size'] > 0 return swap and swap['device_name'] and swap['swap_size'] > 0
def block_device_info_get_image(block_device_info):
block_device_info = block_device_info or {}
# get_disk_mapping() supports block_device_info=None and thus requires that
# we return a list here.
image = block_device_info.get('image') or []
return image
def block_device_info_get_ephemerals(block_device_info): def block_device_info_get_ephemerals(block_device_info):
block_device_info = block_device_info or {} block_device_info = block_device_info or {}
ephemerals = block_device_info.get('ephemerals') or [] ephemerals = block_device_info.get('ephemerals') or []

View File

@ -414,13 +414,7 @@ def get_device_name(bdm):
def get_root_info(instance, virt_type, image_meta, root_bdm, def get_root_info(instance, virt_type, image_meta, root_bdm,
disk_bus, cdrom_bus, root_device_name=None): disk_bus, cdrom_bus, root_device_name=None):
# NOTE (ndipanov): This is a hack to avoid considering an image if root_bdm is None:
# BDM with local target, as we don't support them
# yet. Only applies when passed non-driver format
no_root_bdm = (not root_bdm or (
root_bdm.get('source_type') == 'image' and
root_bdm.get('destination_type') == 'local'))
if no_root_bdm:
# NOTE(mriedem): In case the image_meta object was constructed from # NOTE(mriedem): In case the image_meta object was constructed from
# an empty dict, like in the case of evacuate, we have to first check # an empty dict, like in the case of evacuate, we have to first check
# if disk_format is set on the ImageMeta object. # if disk_format is set on the ImageMeta object.
@ -452,10 +446,13 @@ def default_device_names(virt_type, context, instance, block_device_info,
image_meta): image_meta):
get_disk_info(virt_type, instance, image_meta, block_device_info) get_disk_info(virt_type, instance, image_meta, block_device_info)
for driver_bdm in itertools.chain(block_device_info['ephemerals'], for driver_bdm in itertools.chain(
[block_device_info['swap']] if block_device_info['image'],
block_device_info['swap'] else [], block_device_info['ephemerals'],
block_device_info['block_device_mapping']): [block_device_info['swap']] if
block_device_info['swap'] else [],
block_device_info['block_device_mapping']
):
driver_bdm.save() driver_bdm.save()
@ -563,41 +560,48 @@ def _get_disk_mapping(virt_type, instance, disk_bus, cdrom_bus, image_meta,
:returns: Disk mapping for the given instance. :returns: Disk mapping for the given instance.
""" """
mapping = {} mapping = {}
pre_assigned_device_names = \
[block_device.strip_dev(get_device_name(bdm)) for bdm in itertools.chain( driver_bdms = itertools.chain(
driver.block_device_info_get_image(block_device_info),
driver.block_device_info_get_ephemerals(block_device_info), driver.block_device_info_get_ephemerals(block_device_info),
[driver.block_device_info_get_swap(block_device_info)], [driver.block_device_info_get_swap(block_device_info)],
driver.block_device_info_get_mapping(block_device_info)) driver.block_device_info_get_mapping(block_device_info)
if get_device_name(bdm)] )
# NOTE (ndipanov): root_bdm can be None when we boot from image pre_assigned_device_names = [
# as there is no driver representation of local targeted images block_device.strip_dev(get_device_name(bdm))
# and they will not be in block_device_info list. for bdm in driver_bdms if get_device_name(bdm)
root_bdm = block_device.get_root_bdm( ]
driver.block_device_info_get_mapping(block_device_info))
# Try to find the root driver bdm, either an image based disk or volume
root_bdm = None
if any(driver.block_device_info_get_image(block_device_info)):
root_bdm = driver.block_device_info_get_image(block_device_info)[0]
elif driver.block_device_info_get_mapping(block_device_info):
root_bdm = block_device.get_root_bdm(
driver.block_device_info_get_mapping(block_device_info))
root_device_name = block_device.strip_dev( root_device_name = block_device.strip_dev(
driver.block_device_info_get_root_device(block_device_info)) driver.block_device_info_get_root_device(block_device_info))
root_info = get_root_info( root_info = get_root_info(
instance, virt_type, image_meta, root_bdm, instance, virt_type, image_meta, root_bdm,
disk_bus, cdrom_bus, root_device_name) disk_bus, cdrom_bus, root_device_name)
mapping['root'] = root_info mapping['root'] = root_info
# NOTE (ndipanov): This implicitly relies on image->local BDMs not
# being considered in the driver layer - so missing # NOTE (ft): If device name is not set in root bdm, root_info has a
# bdm with boot_index 0 means - use image, unless it was # generated one. We have to copy device name to root bdm to prevent its
# overridden. This can happen when using legacy syntax and # second generation in loop through bdms. If device name is already
# no root_device_name is set on the instance. # set, nothing is changed.
if not root_bdm and not block_device.volume_in_mapping(root_info['dev'], # NOTE(melwitt): root_bdm can be None in the case of a ISO root device, for
block_device_info): # example.
mapping['disk'] = root_info if root_bdm:
elif root_bdm:
# NOTE (ft): If device name is not set in root bdm, root_info has a
# generated one. We have to copy device name to root bdm to prevent its
# second generation in loop through bdms. If device name is already
# set, nothing is changed.
update_bdm(root_bdm, root_info) update_bdm(root_bdm, root_info)
if (
driver.block_device_info_get_image(block_device_info) or
root_bdm is None
):
mapping['disk'] = root_info
default_eph = get_default_ephemeral_info(instance, disk_bus, default_eph = get_default_ephemeral_info(instance, disk_bus,
block_device_info, mapping) block_device_info, mapping)
if default_eph: if default_eph: