summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/source/reference/block-device-structs.rst9
-rw-r--r--nova/compute/manager.py5
-rw-r--r--nova/tests/unit/compute/test_compute.py29
-rw-r--r--nova/tests/unit/virt/libvirt/test_blockinfo.py89
-rw-r--r--nova/tests/unit/virt/libvirt/test_driver.py5
-rw-r--r--nova/tests/unit/virt/test_block_device.py54
-rw-r--r--nova/virt/block_device.py50
-rw-r--r--nova/virt/driver.py11
-rw-r--r--nova/virt/libvirt/blockinfo.py74
9 files changed, 242 insertions, 84 deletions
diff --git a/doc/source/reference/block-device-structs.rst b/doc/source/reference/block-device-structs.rst
index 1b8636c537..8c2508539f 100644
--- a/doc/source/reference/block-device-structs.rst
+++ b/doc/source/reference/block-device-structs.rst
@@ -71,6 +71,8 @@ called ``block_device_info``, and is generated by
``root_device_name``
Hypervisor's notion of the root device's name
+``image``
+ An image backed disk if used
``ephemerals``
A list of all ephemeral disks
``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
``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
===========================================
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 9f8479a30e..fc720e2429 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -2025,6 +2025,7 @@ class ComputeManager(manager.Manager):
ephemerals = []
swap = []
block_device_mapping = []
+ image = []
for device in block_devices:
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):
block_device_mapping.append(device)
+ if driver_block_device.is_local_image(device):
+ image.append(device)
+
self._default_device_names_for_instance(instance,
root_device_name,
+ image,
ephemerals,
swap,
block_device_mapping)
diff --git a/nova/tests/unit/compute/test_compute.py b/nova/tests/unit/compute/test_compute.py
index 0351166991..43fcdf501b 100644
--- a/nova/tests/unit/compute/test_compute.py
+++ b/nova/tests/unit/compute/test_compute.py
@@ -1389,13 +1389,14 @@ class ComputeVolumeTestCase(BaseTestCase):
@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_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, 'attach_block_devices')
def test_prep_block_device_with_blanks(self, attach_block_devices,
- convert_swap, convert_ephemerals,
- convert_volumes, convert_snapshots,
- convert_images, convert_blanks,
- get_swap):
+ convert_swap, convert_local_images,
+ convert_ephemerals, convert_volumes,
+ convert_snapshots, convert_images,
+ convert_blanks, get_swap):
instance = self._create_fake_instance_obj()
instance['root_device_name'] = '/dev/vda'
root_volume = objects.BlockDeviceMapping(
@@ -1426,6 +1427,7 @@ class ComputeVolumeTestCase(BaseTestCase):
return bdm
convert_swap.return_value = []
+ convert_local_images.return_value = []
convert_ephemerals.return_value = []
convert_volumes.return_value = [blank_volume1, blank_volume2]
convert_snapshots.return_value = []
@@ -1438,6 +1440,7 @@ class ComputeVolumeTestCase(BaseTestCase):
'root_device_name': '/dev/vda',
'swap': [],
'ephemerals': [],
+ 'image': [],
'block_device_mapping': bdms
}
@@ -1452,6 +1455,7 @@ class ComputeVolumeTestCase(BaseTestCase):
self.assertIsNotNone(bdm.device_name)
convert_swap.assert_called_once_with(bdms)
+ convert_local_images.assert_called_once_with(bdms)
convert_ephemerals.assert_called_once_with(bdms)
bdm_args = tuple(bdms)
convert_volumes.assert_called_once_with(bdm_args)
@@ -3212,6 +3216,7 @@ class ComputeTestCase(BaseTestCase,
expected = {
'swap': None,
'ephemerals': [],
+ 'image': [],
'root_device_name': None,
'block_device_mapping': driver_bdms
}
@@ -3240,6 +3245,7 @@ class ComputeTestCase(BaseTestCase,
expected = {
'swap': None,
'ephemerals': [],
+ 'image': [],
'root_device_name': None,
'block_device_mapping': driver_bdms
}
@@ -3318,6 +3324,7 @@ class ComputeTestCase(BaseTestCase,
'size': 2
}
],
+ 'image': [],
'block_device_mapping': [],
'root_device_name': None
}
@@ -6108,7 +6115,7 @@ class ComputeTestCase(BaseTestCase,
mock_pre.assert_called_once_with(
test.MatchType(nova.context.RequestContext),
test.MatchType(objects.Instance),
- {'swap': None, 'ephemerals': [],
+ {'swap': None, 'ephemerals': [], 'image': [],
'root_device_name': None,
'block_device_mapping': []},
mock.ANY, mock.ANY, mock.ANY)
@@ -6474,7 +6481,7 @@ class ComputeTestCase(BaseTestCase,
self.assertEqual(2, mock_notify.call_count)
post_live_migration.assert_has_calls([
mock.call(c, instance, {'swap': None, 'ephemerals': [],
- 'root_device_name': None,
+ 'image': [], 'root_device_name': None,
'block_device_mapping': []},
migrate_data)])
migrate_instance_start.assert_has_calls([
@@ -6705,7 +6712,7 @@ class ComputeTestCase(BaseTestCase,
mock_setup.assert_called_once_with(c, instance, self.compute.host,
teardown=True)
mock_rollback.assert_called_once_with(c, instance, [],
- {'swap': None, 'ephemerals': [],
+ {'swap': None, 'ephemerals': [], 'image': [],
'root_device_name': None,
'block_device_mapping': []},
destroy_disks=True, migrate_data=None)
@@ -8134,7 +8141,7 @@ class ComputeTestCase(BaseTestCase,
self.compute._default_block_device_names(instance, {}, bdms)
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])
@mock.patch.object(objects.BlockDeviceMapping, 'save')
@@ -8148,7 +8155,7 @@ class ComputeTestCase(BaseTestCase,
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])
@mock.patch.object(objects.Instance, 'save')
@@ -8170,7 +8177,7 @@ class ComputeTestCase(BaseTestCase,
self.assertEqual('/dev/vda', instance.root_device_name)
mock_default_dev.assert_called_once_with(instance, mock.ANY, bdms[0])
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):
instance = self._create_fake_instance_obj()
@@ -8230,7 +8237,7 @@ class ComputeTestCase(BaseTestCase,
self.assertEqual('/dev/vda', instance.root_device_name)
self.assertTrue(object_save.called)
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]])
def test_reserve_block_device_name(self):
diff --git a/nova/tests/unit/virt/libvirt/test_blockinfo.py b/nova/tests/unit/virt/libvirt/test_blockinfo.py
index 3da827dce8..9505dbe31c 100644
--- a/nova/tests/unit/virt/libvirt/test_blockinfo.py
+++ b/nova/tests/unit/virt/libvirt/test_blockinfo.py
@@ -74,6 +74,7 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
def _test_block_device_info(self, with_eph=True, with_swap=True,
with_bdms=True):
swap = {'device_name': '/dev/vdb', 'swap_size': 1}
+ image = [{'device_type': 'disk', 'boot_index': 0}]
ephemerals = [{'device_type': 'disk', 'guest_format': 'ext4',
'device_name': '/dev/vdc1', 'size': 10},
{'disk_bus': 'ide', 'guest_format': None,
@@ -84,6 +85,7 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
'device_path': 'fake_device'}]
return {'root_device_name': '/dev/vda',
'swap': swap if with_swap else {},
+ 'image': image,
'ephemerals': ephemerals if with_eph else [],
'block_device_mapping':
block_device_mapping if with_bdms else []}
@@ -178,11 +180,16 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
instance_ref = objects.Instance(**self.test_instance)
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',
return_value=instance_ref.flavor) as get_flavor:
- mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
- "virtio", "ide",
- image_meta)
+ mapping = blockinfo.get_disk_mapping(
+ "kvm", instance_ref, "virtio", "ide", image_meta,
+ block_device_info=block_device_info)
# 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.
get_flavor.assert_called_once_with()
@@ -202,7 +209,8 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
instance_ref = objects.Instance(**self.test_instance)
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
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,
@@ -490,9 +498,12 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
instance_ref = objects.Instance(**self.test_instance)
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
- mapping = blockinfo.get_disk_mapping("lxc", instance_ref,
- "lxc", "lxc",
- image_meta)
+ block_device_info = {
+ 'image': [{'device_type': 'disk', 'boot_index': 0}],
+ }
+ mapping = blockinfo.get_disk_mapping(
+ "lxc", instance_ref, "lxc", "lxc", image_meta,
+ block_device_info=block_device_info)
expect = {
'disk': {'bus': 'lxc', 'dev': None,
'type': 'disk', 'boot_index': '1'},
@@ -527,9 +538,14 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
instance_ref.flavor.swap = 5
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
- mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
- "virtio", "ide",
- image_meta)
+ block_device_info = {
+ 'image': [
+ {'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 = {
'disk': {'bus': 'virtio', 'dev': 'vda',
@@ -549,6 +565,7 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
instance_ref.ephemeral_gb = 0
block_dev_info = {'swap': None, 'root_device_name': u'/dev/vda',
+ 'image': [],
'ephemerals': [],
'block_device_mapping': [{'boot_index': None,
'mount_device': u'/dev/vdb',
@@ -591,8 +608,14 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
instance_ref = objects.Instance(**self.test_instance)
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(
- "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
# 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)
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(
- "kvm", instance_ref, "virtio", "ide", image_meta)
+ "kvm", instance_ref, "virtio", "ide", image_meta,
+ block_device_info=block_device_info)
expect = {
'disk': {
@@ -697,9 +726,14 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
instance_ref = objects.Instance(**self.test_instance)
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
- mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
- "virtio", "ide",
- image_meta)
+ block_device_info = {
+ 'image': [
+ {'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 = {
'disk': {'bus': 'virtio', 'dev': 'vda',
@@ -718,6 +752,9 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
block_device_info = {
+ 'image': [
+ {'device_type': 'disk', 'boot_index': 0},
+ ],
'ephemerals': [
{'device_type': 'disk', 'guest_format': 'ext4',
'device_name': '/dev/vdb', 'size': 10},
@@ -754,6 +791,8 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
block_device_info = {
'swap': {'device_name': '/dev/vdb',
'swap_size': 10},
+ 'image': [{'device_type': 'disk',
+ 'boot_index': 0}],
}
mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
"virtio", "ide",
@@ -775,6 +814,7 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
block_device_info = {
+ 'image': [],
'block_device_mapping': [
{'connection_info': "fake",
'mount_device': "/dev/vda",
@@ -803,6 +843,7 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
image_meta = {}
block_device_info = {
+ 'image': [],
'block_device_mapping': [
{'connection_info': None,
'mount_device': None,
@@ -858,6 +899,7 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
block_device_info = {
+ 'image': [],
'block_device_mapping': [
{'connection_info': "fake",
'mount_device': "/dev/vda",
@@ -899,6 +941,7 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
'root_device_name': '/dev/vdf',
'swap': {'device_name': '/dev/vdy',
'swap_size': 10},
+ 'image': [{'device_type': 'disk', 'boot_index': 0}],
'ephemerals': [
{'device_type': 'disk', 'guest_format': 'ext4',
'device_name': '/dev/vdb', 'size': 10},
@@ -940,6 +983,8 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
'swap': {'device_name': '/dev/vdb',
'device_type': 'really_lame_type',
'swap_size': 10},
+ 'image': [{'device_name': '/dev/vda',
+ 'device_type': 'disk'}],
'ephemerals': [{'disk_bus': 'no_such_bus',
'device_type': 'yeah_right',
'device_name': '/dev/vdc', 'size': 10}],
@@ -951,6 +996,8 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
}
expected_swap = {'device_name': '/dev/vdb', 'disk_bus': 'virtio',
'device_type': 'disk', 'swap_size': 10}
+ expected_image = {'device_name': '/dev/vda', 'device_type': 'disk',
+ 'disk_bus': 'virtio'}
expected_ephemeral = {'disk_bus': 'virtio',
'device_type': 'disk',
'device_name': '/dev/vdc', 'size': 10}
@@ -970,6 +1017,7 @@ class LibvirtBlockInfoTest(test.NoDBTestCase):
self.assertFalse(get_flavor_mock.called)
self.assertEqual(expected_swap, block_device_info['swap'])
+ self.assertEqual(expected_image, block_device_info['image'][0])
self.assertEqual(expected_ephemeral,
block_device_info['ephemerals'][0])
self.assertEqual(expected_bdm,
@@ -1441,6 +1489,15 @@ class DefaultDeviceNamesTestCase(test.NoDBTestCase):
'destination_type': 'volume',
'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):
super(DefaultDeviceNamesTestCase, self).tearDown()
for patcher in self.patchers:
@@ -1450,7 +1507,7 @@ class DefaultDeviceNamesTestCase(test.NoDBTestCase):
'nova.virt.libvirt.utils.get_arch',
return_value=obj_fields.Architecture.X86_64)
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)
blockinfo.default_device_names(self.virt_type,
self.context,
diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py
index 7f73e45fd7..30af4e3e2f 100644
--- a/nova/tests/unit/virt/libvirt/test_driver.py
+++ b/nova/tests/unit/virt/libvirt/test_driver.py
@@ -20410,7 +20410,7 @@ class LibvirtConnTestCase(test.NoDBTestCase,
**fake_block_device.FakeDbBlockDeviceDict(
{'id': 0,
'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(
[bdm])}
info['block_device_mapping'][0]['connection_info'] = conn_info
@@ -24941,7 +24941,8 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
'id': 1,
'source_type': 'volume',
'destination_type': 'volume',
- 'device_name': '/dev/vda'}))
+ 'device_name': '/dev/vda',
+ 'boot_index': 0}))
bdms = driver_block_device.convert_volumes([bdm])
block_device_info = {'root_device_name': '/dev/vda',
'ephemerals': [],
diff --git a/nova/tests/unit/virt/test_block_device.py b/nova/tests/unit/virt/test_block_device.py
index 79dbc44bf1..fe74744ec5 100644
--- a/nova/tests/unit/virt/test_block_device.py
+++ b/nova/tests/unit/virt/test_block_device.py
@@ -49,7 +49,8 @@ class TestDriverBlockDevice(test.NoDBTestCase):
'volume': driver_block_device.DriverVolumeBlockDevice,
'volsnapshot': driver_block_device.DriverVolSnapshotBlockDevice,
'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(
@@ -210,6 +211,27 @@ class TestDriverBlockDevice(test.NoDBTestCase):
'boot_index': -1,
'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):
super(TestDriverBlockDevice, self).setUp()
self.volume_api = mock.MagicMock(autospec=cinder.API)
@@ -219,6 +241,8 @@ class TestDriverBlockDevice(test.NoDBTestCase):
# create bdm objects for testing
self.swap_bdm = fake_block_device.fake_bdm_object(
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.context, self.ephemeral_bdm_dict)
self.volume_bdm = fake_block_device.fake_bdm_object(
@@ -337,6 +361,10 @@ class TestDriverBlockDevice(test.NoDBTestCase):
if field == 'attachment_id':
# Must set UUID values on UUID fields.
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:
fake_value = 'fake_changed_value'
test_bdm[field] = fake_value
@@ -377,6 +405,20 @@ class TestDriverBlockDevice(test.NoDBTestCase):
def test_driver_swap_default_size(self):
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):
self._test_driver_device("ephemeral")
@@ -406,7 +448,7 @@ class TestDriverBlockDevice(test.NoDBTestCase):
self.assertEqual(test_bdm.volume_size, 3)
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')
test_bdm = self.driver_classes['volimage'](
@@ -416,7 +458,7 @@ class TestDriverBlockDevice(test.NoDBTestCase):
self.assertEqual(test_bdm.volume_size, 1)
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')
bdm = self.volimage_bdm_dict.copy()
bdm['destination_type'] = 'local'
@@ -1263,12 +1305,8 @@ class TestDriverBlockDevice(test.NoDBTestCase):
def test_is_implemented(self):
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))
- 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):
test_swap = self.driver_classes['swap'](self.swap_bdm)
diff --git a/nova/virt/block_device.py b/nova/virt/block_device.py
index 4a41703174..df354ec65d 100644
--- a/nova/virt/block_device.py
+++ b/nova/virt/block_device.py
@@ -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):
_new_only_fields = set(['disk_bus', 'device_type', 'guest_format'])
_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,
DriverSwapBlockDevice)
+convert_local_images = functools.partial(_convert_block_devices,
+ DriverImageBlockDevice)
convert_ephemerals = functools.partial(_convert_block_devices,
DriverEphemeralBlockDevice)
-
convert_volumes = functools.partial(_convert_block_devices,
DriverVolumeBlockDevice)
-
convert_snapshots = functools.partial(_convert_block_devices,
DriverVolSnapshotBlockDevice)
@@ -897,9 +927,15 @@ def get_swap(transformed_list):
return None
-_IMPLEMENTED_CLASSES = (DriverSwapBlockDevice, DriverEphemeralBlockDevice,
- DriverVolumeBlockDevice, DriverVolSnapshotBlockDevice,
- DriverVolImageBlockDevice, DriverVolBlankBlockDevice)
+_IMPLEMENTED_CLASSES = (
+ DriverSwapBlockDevice,
+ DriverEphemeralBlockDevice,
+ DriverVolumeBlockDevice,
+ DriverVolSnapshotBlockDevice,
+ DriverVolImageBlockDevice,
+ DriverVolBlankBlockDevice,
+ DriverImageBlockDevice
+)
def is_implemented(bdm):
@@ -912,6 +948,10 @@ def is_implemented(bdm):
return False
+def is_local_image(bdm):
+ return bdm.source_type == 'image' and bdm.destination_type == 'local'
+
+
def is_block_device_mapping(bdm):
return (bdm.source_type in ('image', 'volume', 'snapshot', 'blank') and
bdm.destination_type == 'volume' and
diff --git a/nova/virt/driver.py b/nova/virt/driver.py
index 23d0b54f18..301d93b148 100644
--- a/nova/virt/driver.py
+++ b/nova/virt/driver.py
@@ -44,6 +44,7 @@ def get_block_device_info(instance, block_device_mapping):
of a dict containing the following keys:
- root_device_name: device name of the root disk
+ - image: An instance of DriverImageBlockDevice or None
- ephemerals: a (potentially empty) list of DriverEphemeralBlockDevice
instances
- 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
return {
'root_device_name': instance.root_device_name,
+ 'image': virt_block_device.convert_local_images(
+ block_device_mapping),
'ephemerals': virt_block_device.convert_ephemerals(
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
+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):
block_device_info = block_device_info or {}
ephemerals = block_device_info.get('ephemerals') or []
diff --git a/nova/virt/libvirt/blockinfo.py b/nova/virt/libvirt/blockinfo.py
index f86a9c461c..9a4aa671be 100644
--- a/nova/virt/libvirt/blockinfo.py
+++ b/nova/virt/libvirt/blockinfo.py
@@ -414,13 +414,7 @@ def get_device_name(bdm):
def get_root_info(instance, virt_type, image_meta, root_bdm,
disk_bus, cdrom_bus, root_device_name=None):
- # NOTE (ndipanov): This is a hack to avoid considering an image
- # 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:
+ if root_bdm is None:
# 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
# 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):
get_disk_info(virt_type, instance, image_meta, block_device_info)
- for driver_bdm in itertools.chain(block_device_info['ephemerals'],
- [block_device_info['swap']] if
- block_device_info['swap'] else [],
- block_device_info['block_device_mapping']):
+ for driver_bdm in itertools.chain(
+ block_device_info['image'],
+ block_device_info['ephemerals'],
+ [block_device_info['swap']] if
+ block_device_info['swap'] else [],
+ block_device_info['block_device_mapping']
+ ):
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.
"""
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_swap(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
- # as there is no driver representation of local targeted images
- # and they will not be in block_device_info list.
- root_bdm = block_device.get_root_bdm(
- driver.block_device_info_get_mapping(block_device_info))
+ driver.block_device_info_get_mapping(block_device_info)
+ )
+ pre_assigned_device_names = [
+ block_device.strip_dev(get_device_name(bdm))
+ for bdm in driver_bdms if get_device_name(bdm)
+ ]
+
+ # 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(
driver.block_device_info_get_root_device(block_device_info))
root_info = get_root_info(
instance, virt_type, image_meta, root_bdm,
disk_bus, cdrom_bus, root_device_name)
-
mapping['root'] = root_info
- # NOTE (ndipanov): This implicitly relies on image->local BDMs not
- # being considered in the driver layer - so missing
- # bdm with boot_index 0 means - use image, unless it was
- # overridden. This can happen when using legacy syntax and
- # no root_device_name is set on the instance.
- if not root_bdm and not block_device.volume_in_mapping(root_info['dev'],
- block_device_info):
- mapping['disk'] = root_info
- 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.
+
+ # 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.
+ # NOTE(melwitt): root_bdm can be None in the case of a ISO root device, for
+ # example.
+ if root_bdm:
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,
block_device_info, mapping)
if default_eph: