Make compute API create() use BDM objects

Once we have consolidated all the block device information for an
instance coming from different sources (request, image metadata) we turn
them into objects and use objects update_or_create() for saving them into
the database.

Blueprint: kilo-objects

Change-Id: I9a70761d6a0a448cfbaf7102c45d6dc180a4cdea
This commit is contained in:
Nikola Dipanov 2014-06-07 21:31:41 +02:00
parent c11cd4fa26
commit 220ba7dbbc
12 changed files with 180 additions and 106 deletions

View File

@ -74,7 +74,7 @@ class CellsManager(manager.Manager):
Scheduling requests get passed to the scheduler class.
"""
target = oslo_messaging.Target(version='1.33')
target = oslo_messaging.Target(version='1.34')
def __init__(self, *args, **kwargs):
LOG.warning(_LW('The cells feature of Nova is considered experimental '

View File

@ -106,6 +106,8 @@ class CellsAPI(object):
* 1.31 - Add clean_shutdown to stop, resize, rescue, and shelve
* 1.32 - Send objects for instances in build_instances()
* 1.33 - Add clean_shutdown to resize_instance()
* 1.34 - build_instances uses BlockDeviceMapping objects, drops
legacy_bdm argument
'''
VERSION_ALIASES = {
@ -153,7 +155,15 @@ class CellsAPI(object):
instances = build_inst_kwargs['instances']
build_inst_kwargs['image'] = jsonutils.to_primitive(
build_inst_kwargs['image'])
version = '1.32'
version = '1.34'
if self.client.can_send_version('1.34'):
build_inst_kwargs.pop('legacy_bdm', None)
else:
bdm_p = objects_base.obj_to_primitive(
build_inst_kwargs['block_device_mapping'])
build_inst_kwargs['block_device_mapping'] = bdm_p
version = '1.32'
if not self.client.can_send_version('1.32'):
instances_p = [jsonutils.to_primitive(inst) for inst in instances]
build_inst_kwargs['instances'] = instances_p

View File

@ -20,6 +20,7 @@
networking and storage of VMs, and compute hosts on which they run)."""
import base64
import copy
import functools
import re
import string
@ -62,6 +63,7 @@ from nova.network.security_group import security_group_base
from nova import notifications
from nova import objects
from nova.objects import base as obj_base
from nova.objects import block_device as block_device_obj
from nova.objects import keypair as keypair_obj
from nova.objects import quotas as quotas_obj
from nova.objects import security_group as security_group_obj
@ -705,9 +707,9 @@ class API(base.Base):
return image_defined_bdms
def _check_and_transform_bdm(self, base_options, instance_type, image_meta,
min_count, max_count, block_device_mapping,
legacy_bdm):
def _check_and_transform_bdm(self, context, base_options, instance_type,
image_meta, min_count, max_count,
block_device_mapping, legacy_bdm):
# NOTE (ndipanov): Assume root dev name is 'vda' if not supplied.
# It's needed for legacy conversion to work.
root_device_name = (base_options.get('root_device_name') or 'vda')
@ -758,7 +760,8 @@ class API(base.Base):
' instances')
raise exception.InvalidRequest(msg)
return block_device_mapping
return block_device_obj.block_device_make_list_from_dicts(
context, block_device_mapping)
def _get_image(self, context, image_href):
if not image_href:
@ -783,7 +786,6 @@ class API(base.Base):
user_data, metadata, injected_files,
access_ip_v4, access_ip_v6,
requested_networks, config_drive,
block_device_mapping,
auto_disk_config, reservation_id,
max_count):
"""Verify all the input parameters regardless of the provisioning
@ -1097,8 +1099,7 @@ class API(base.Base):
key_name, key_data, security_groups, availability_zone,
forced_host, user_data, metadata, injected_files, access_ip_v4,
access_ip_v6, requested_networks, config_drive,
block_device_mapping, auto_disk_config, reservation_id,
max_count)
auto_disk_config, reservation_id, max_count)
# max_net_count is the maximum number of instances requested by the
# user adjusted for any network quota constraints, including
@ -1112,7 +1113,7 @@ class API(base.Base):
'max_net_count': max_net_count})
max_count = max_net_count
block_device_mapping = self._check_and_transform_bdm(
block_device_mapping = self._check_and_transform_bdm(context,
base_options, instance_type, boot_meta, min_count, max_count,
block_device_mapping, legacy_bdm)
@ -1194,34 +1195,33 @@ class API(base.Base):
return prepared_mappings
def _update_block_device_mapping(self, elevated_context,
instance_type, instance_uuid,
def _create_block_device_mapping(self, instance_type, instance_uuid,
block_device_mapping):
"""tell vm driver to attach volume at boot time by updating
BlockDeviceMapping
"""Create the BlockDeviceMapping objects in the db.
This method makes a copy of the list in order to avoid using the same
id field in case this is called for multiple instances.
"""
LOG.debug("block_device_mapping %s", block_device_mapping,
instance_uuid=instance_uuid)
for bdm in block_device_mapping:
bdm['volume_size'] = self._volume_size(instance_type, bdm)
if bdm.get('volume_size') == 0:
instance_block_device_mapping = copy.deepcopy(block_device_mapping)
for bdm in instance_block_device_mapping:
bdm.volume_size = self._volume_size(instance_type, bdm)
if bdm.volume_size == 0:
continue
bdm['instance_uuid'] = instance_uuid
self.db.block_device_mapping_update_or_create(elevated_context,
bdm,
legacy=False)
bdm.instance_uuid = instance_uuid
bdm.update_or_create()
def _validate_bdm(self, context, instance, instance_type, all_mappings):
def _subsequent_list(l):
return all(el + 1 == l[i + 1] for i, el in enumerate(l[:-1]))
# Make sure that the boot indexes make sense
boot_indexes = sorted([bdm['boot_index']
boot_indexes = sorted([bdm.boot_index
for bdm in all_mappings
if bdm.get('boot_index') is not None
and bdm.get('boot_index') >= 0])
if bdm.boot_index is not None
and bdm.boot_index >= 0])
if 0 not in boot_indexes or not _subsequent_list(boot_indexes):
raise exception.InvalidBDMBootSequence()
@ -1230,18 +1230,18 @@ class API(base.Base):
# NOTE(vish): For now, just make sure the volumes are accessible.
# Additionally, check that the volume can be attached to this
# instance.
snapshot_id = bdm.get('snapshot_id')
volume_id = bdm.get('volume_id')
image_id = bdm.get('image_id')
snapshot_id = bdm.snapshot_id
volume_id = bdm.volume_id
image_id = bdm.image_id
if (image_id is not None and
image_id != instance.get('image_ref')):
try:
self._get_image(context, image_id)
except Exception:
raise exception.InvalidBDMImage(id=image_id)
if (bdm['source_type'] == 'image' and
bdm['destination_type'] == 'volume' and
not bdm['volume_size']):
if (bdm.source_type == 'image' and
bdm.destination_type == 'volume' and
not bdm.volume_size):
raise exception.InvalidBDM(message=_("Images with "
"destination_type 'volume' need to have a non-zero "
"size specified"))
@ -1264,7 +1264,7 @@ class API(base.Base):
except Exception:
raise exception.InvalidBDMSnapshot(id=snapshot_id)
ephemeral_size = sum(bdm.get('volume_size') or 0
ephemeral_size = sum(bdm.volume_size or 0
for bdm in all_mappings
if block_device.new_format_is_ephemeral(bdm))
if ephemeral_size > instance_type['ephemeral_gb']:
@ -1278,14 +1278,14 @@ class API(base.Base):
raise exception.InvalidBDMFormat(details=msg)
if swap_list:
swap_size = swap_list[0].get('volume_size') or 0
swap_size = swap_list[0].volume_size or 0
if swap_size > instance_type['swap']:
raise exception.InvalidBDMSwapSize()
max_local = CONF.max_local_block_devices
if max_local >= 0:
num_local = len([bdm for bdm in all_mappings
if bdm.get('destination_type') == 'local'])
if bdm.destination_type == 'local'])
if num_local > max_local:
raise exception.InvalidBDMLocalsLimit()
@ -1400,8 +1400,8 @@ class API(base.Base):
with excutils.save_and_reraise_exception():
instance.destroy()
self._update_block_device_mapping(
context, instance_type, instance['uuid'], block_device_mapping)
self._create_block_device_mapping(
instance_type, instance['uuid'], block_device_mapping)
return instance

View File

@ -199,7 +199,7 @@ class ComputeCellsAPI(compute_api.API):
"""
return super(ComputeCellsAPI, self).create(*args, **kwargs)
def _update_block_device_mapping(self, *args, **kwargs):
def _create_block_device_mapping(self, *args, **kwargs):
"""Don't create block device mappings in the API cell.
The child cell will create it and propagate it up to the parent cell.

View File

@ -199,6 +199,7 @@ class ConductorManager(manager.Manager):
architecture)
return jsonutils.to_primitive(info)
# NOTE(ndipanov): This can be removed in version 3.0 of the RPC API
def block_device_mapping_update_or_create(self, context, values, create):
if create is None:
bdm = self.db.block_device_mapping_update_or_create(context,

View File

@ -449,7 +449,8 @@ class ComputeTaskAPI(object):
kw['requested_networks'] = kw['requested_networks'].as_tuples()
if not self.client.can_send_version('1.7'):
version = '1.5'
kw.update({'block_device_mapping': block_device_mapping,
bdm_p = objects_base.obj_to_primitive(block_device_mapping)
kw.update({'block_device_mapping': bdm_p,
'legacy_bdm': legacy_bdm})
cctxt = self.client.prepare(version=version)

View File

@ -296,3 +296,9 @@ def block_device_make_list(context, db_list, **extra_args):
objects.BlockDeviceMappingList(context),
objects.BlockDeviceMapping, db_list,
**extra_args)
def block_device_make_list_from_dicts(context, bdm_dicts_list):
bdm_objects = [objects.BlockDeviceMapping(context=context, **bdm)
for bdm in bdm_dicts_list]
return BlockDeviceMappingList(objects=bdm_objects)

View File

@ -139,7 +139,7 @@ class CellsAPITestCase(test.NoDBTestCase):
'arg2': 2,
'arg3': 3}}
self._check_result(call_info, 'build_instances',
expected_args, version='1.32')
expected_args, version='1.34')
def test_get_capacities(self):
capacity_info = {"capacity": "info"}

View File

@ -33,6 +33,7 @@ from nova.openstack.common import uuidutils
from nova.scheduler import utils as scheduler_utils
from nova import test
from nova.tests.unit.cells import fakes
from nova.tests.unit import fake_block_device
from nova import utils
CONF = cfg.CONF
@ -115,8 +116,12 @@ class CellsSchedulerTestCase(test.TestCase):
'project_id': self.ctxt.project_id}
call_info = {'uuids': []}
block_device_mapping = [block_device.create_image_bdm(
'fake_image_ref')]
block_device_mapping = [
objects.BlockDeviceMapping(context=self.ctxt,
**fake_block_device.FakeDbBlockDeviceDict(
block_device.create_image_bdm('fake_image_ref'),
anon=True))
]
def _fake_instance_update_at_top(_ctxt, instance):
call_info['uuids'].append(instance['uuid'])

View File

@ -902,7 +902,7 @@ class ComputeVolumeTestCase(BaseTestCase):
instance = self._create_fake_instance_obj()
instance_type = {'swap': 1, 'ephemeral_gb': 2}
mappings = [
{
fake_block_device.FakeDbBlockDeviceDict({
'device_name': '/dev/sdb4',
'source_type': 'blank',
'destination_type': 'local',
@ -910,8 +910,8 @@ class ComputeVolumeTestCase(BaseTestCase):
'guest_format': 'swap',
'boot_index': -1,
'volume_size': 1
},
{
}, anon=True),
fake_block_device.FakeDbBlockDeviceDict({
'device_name': '/dev/sda1',
'source_type': 'volume',
'destination_type': 'volume',
@ -920,8 +920,8 @@ class ComputeVolumeTestCase(BaseTestCase):
'guest_format': None,
'boot_index': 1,
'volume_size': 6
},
{
}, anon=True),
fake_block_device.FakeDbBlockDeviceDict({
'device_name': '/dev/sda2',
'source_type': 'snapshot',
'destination_type': 'volume',
@ -930,8 +930,8 @@ class ComputeVolumeTestCase(BaseTestCase):
'guest_format': None,
'boot_index': 0,
'volume_size': 4
},
{
}, anon=True),
fake_block_device.FakeDbBlockDeviceDict({
'device_name': '/dev/sda3',
'source_type': 'image',
'destination_type': 'local',
@ -939,20 +939,22 @@ class ComputeVolumeTestCase(BaseTestCase):
'guest_format': None,
'boot_index': 2,
'volume_size': 1
}
}, anon=True)
]
mappings = block_device_obj.block_device_make_list_from_dicts(
self.context, mappings)
# Make sure it passes at first
self.compute_api._validate_bdm(self.context, instance,
instance_type, mappings)
# Boot sequence
mappings[2]['boot_index'] = 2
mappings[2].boot_index = 2
self.assertRaises(exception.InvalidBDMBootSequence,
self.compute_api._validate_bdm,
self.context, instance, instance_type,
mappings)
mappings[2]['boot_index'] = 0
mappings[2].boot_index = 0
# number of local block_devices
self.flags(max_local_block_devices=1)
@ -961,7 +963,7 @@ class ComputeVolumeTestCase(BaseTestCase):
self.context, instance, instance_type,
mappings)
ephemerals = [
{
fake_block_device.FakeDbBlockDeviceDict({
'device_name': '/dev/vdb',
'source_type': 'blank',
'destination_type': 'local',
@ -970,8 +972,8 @@ class ComputeVolumeTestCase(BaseTestCase):
'guest_format': None,
'boot_index': -1,
'volume_size': 1
},
{
}, anon=True),
fake_block_device.FakeDbBlockDeviceDict({
'device_name': '/dev/vdc',
'source_type': 'blank',
'destination_type': 'local',
@ -980,34 +982,37 @@ class ComputeVolumeTestCase(BaseTestCase):
'guest_format': None,
'boot_index': -1,
'volume_size': 1
}]
}, anon=True)
]
ephemerals = block_device_obj.block_device_make_list_from_dicts(
self.context, ephemerals)
self.flags(max_local_block_devices=4)
# More ephemerals are OK as long as they are not over the size limit
mappings_ = mappings[:]
mappings_.objects.extend(ephemerals)
self.compute_api._validate_bdm(self.context, instance,
instance_type, mappings + ephemerals)
instance_type, mappings_)
# Ephemerals over the size limit
ephemerals[0]['volume_size'] = 3
ephemerals[0].volume_size = 3
mappings_ = mappings[:]
mappings_.objects.extend(ephemerals)
self.assertRaises(exception.InvalidBDMEphemeralSize,
self.compute_api._validate_bdm,
self.context, instance, instance_type,
mappings + ephemerals)
self.assertRaises(exception.InvalidBDMEphemeralSize,
self.compute_api._validate_bdm,
self.context, instance, instance_type,
mappings + [ephemerals[0]])
mappings_)
# Swap over the size limit
mappings[0]['volume_size'] = 3
mappings[0].volume_size = 3
self.assertRaises(exception.InvalidBDMSwapSize,
self.compute_api._validate_bdm,
self.context, instance, instance_type,
mappings)
mappings[0]['volume_size'] = 1
mappings[0].volume_size = 1
additional_swap = [
{
fake_block_device.FakeDbBlockDeviceDict({
'device_name': '/dev/vdb',
'source_type': 'blank',
'destination_type': 'local',
@ -1015,31 +1020,42 @@ class ComputeVolumeTestCase(BaseTestCase):
'guest_format': 'swap',
'boot_index': -1,
'volume_size': 1
}]
}, anon=True)
]
additional_swap = block_device_obj.block_device_make_list_from_dicts(
self.context, additional_swap)
# More than one swap
mappings_ = mappings[:]
mappings_.objects.extend(additional_swap)
self.assertRaises(exception.InvalidBDMFormat,
self.compute_api._validate_bdm,
self.context, instance, instance_type,
mappings + additional_swap)
mappings_)
image_no_size = [
{
fake_block_device.FakeDbBlockDeviceDict({
'device_name': '/dev/sda4',
'source_type': 'image',
'image_id': image_id,
'destination_type': 'volume',
'boot_index': -1,
'volume_size': None,
}]
}, anon=True)
]
image_no_size = block_device_obj.block_device_make_list_from_dicts(
self.context, image_no_size)
mappings_ = mappings[:]
mappings_.objects.extend(image_no_size)
self.assertRaises(exception.InvalidBDM,
self.compute_api._validate_bdm,
self.context, instance, instance_type,
mappings + image_no_size)
mappings_)
def test_validate_bdm_media_service_exceptions(self):
instance_type = {'swap': 1, 'ephemeral_gb': 1}
all_mappings = [{'id': 1,
all_mappings = [fake_block_device.FakeDbBlockDeviceDict({
'id': 1,
'no_device': None,
'source_type': 'volume',
'destination_type': 'volume',
@ -1047,7 +1063,9 @@ class ComputeVolumeTestCase(BaseTestCase):
'volume_id': self.volume_id,
'device_name': 'vda',
'boot_index': 0,
'delete_on_termination': False}]
'delete_on_termination': False}, anon=True)]
all_mappings = block_device_obj.block_device_make_list_from_dicts(
self.context, all_mappings)
# First we test a list of invalid status values that should result
# in an InvalidVolume exception being raised.
@ -8312,7 +8330,12 @@ class ComputeAPITestCase(BaseTestCase):
return bdm
def test_update_block_device_mapping(self):
def test_create_block_device_mapping(self):
def _compare_bdm_object(obj1, obj2, extra_keys=()):
for key in (('device_name', 'source_type', 'destination_type')
+ extra_keys):
self.assertEqual(getattr(obj1, key), getattr(obj2, key))
swap_size = ephemeral_size = 1
instance_type = {'swap': swap_size, 'ephemeral_gb': ephemeral_size}
instance = self._create_fake_instance_obj()
@ -8377,12 +8400,13 @@ class ComputeAPITestCase(BaseTestCase):
image_mapping = self.compute_api._prepare_image_mapping(
instance_type, mappings)
self.compute_api._update_block_device_mapping(
self.context, instance_type, instance['uuid'], image_mapping)
image_mapping = block_device_obj.block_device_make_list_from_dicts(
self.context, image_mapping)
self.compute_api._create_block_device_mapping(
instance_type, instance['uuid'], image_mapping)
bdms = [block_device.BlockDeviceDict(bdm) for bdm in
db.block_device_mapping_get_all_by_instance(
self.context, instance['uuid'])]
bdms = block_device_obj.BlockDeviceMappingList.get_by_instance_uuid(
self.context, instance['uuid'])
expected_result = [
{'source_type': 'blank', 'destination_type': 'local',
'guest_format': 'swap', 'device_name': '/dev/sdb1',
@ -8397,21 +8421,32 @@ class ComputeAPITestCase(BaseTestCase):
'guest_format': CONF.default_ephemeral_format,
'device_name': '/dev/sdc2', 'delete_on_termination': True},
]
bdms.sort(key=operator.itemgetter('device_name'))
expected_result.sort(key=operator.itemgetter('device_name'))
expected_result = block_device_obj.block_device_make_list_from_dicts(
self.context,
map(fake_block_device.AnonFakeDbBlockDeviceDict,
expected_result))
bdms.sort(key=operator.attrgetter('device_name'))
expected_result.sort(key=operator.attrgetter('device_name'))
self.assertEqual(len(bdms), len(expected_result))
for expected, got in zip(expected_result, bdms):
self.assertThat(expected, matchers.IsSubDictOf(got))
_compare_bdm_object(
expected, got,
extra_keys=('guest_format', 'delete_on_termination'))
self.compute_api._update_block_device_mapping(
self.context, flavors.get_default_flavor(),
instance['uuid'], block_device_mapping)
bdms = [block_device.BlockDeviceDict(bdm) for bdm in
db.block_device_mapping_get_all_by_instance(
self.context, instance['uuid'])]
block_device_mapping = (
block_device_obj.block_device_make_list_from_dicts(
self.context,
map(fake_block_device.AnonFakeDbBlockDeviceDict,
block_device_mapping)))
self.compute_api._create_block_device_mapping(
flavors.get_default_flavor(), instance['uuid'],
block_device_mapping)
bdms = block_device_obj.BlockDeviceMappingList.get_by_instance_uuid(
self.context, instance['uuid'])
expected_result = [
{'snapshot_id': '00000000-aaaa-bbbb-cccc-000000000000',
'device_name': '/dev/sda1'},
'device_name': '/dev/sda1', 'source_type': 'snapshot',
'destination_type': 'volume'},
{'source_type': 'blank', 'destination_type': 'local',
'guest_format': 'swap', 'device_name': '/dev/sdb1',
@ -8449,11 +8484,17 @@ class ComputeAPITestCase(BaseTestCase):
'source_type': 'snapshot', 'destination_type': 'volume',
'snapshot_id': '77777777-aaaa-bbbb-cccc-888888888888'},
{'no_device': True, 'device_name': '/dev/sdd4'}]
expected_result = block_device_obj.block_device_make_list_from_dicts(
self.context,
map(fake_block_device.AnonFakeDbBlockDeviceDict,
expected_result))
bdms.sort(key=operator.itemgetter('device_name'))
expected_result.sort(key=operator.itemgetter('device_name'))
self.assertEqual(len(bdms), len(expected_result))
for expected, got in zip(expected_result, bdms):
self.assertThat(expected, matchers.IsSubDictOf(got))
_compare_bdm_object(
expected, got,
extra_keys=('snapshot_id', 'delete_on_termination'))
def _test_check_and_transform_bdm(self, bdms, expected_bdms,
image_bdms=None, base_options=None,
@ -8468,9 +8509,11 @@ class ComputeAPITestCase(BaseTestCase):
base_options = base_options or {'root_device_name': 'vda',
'image_ref': FAKE_IMAGE_REF}
transformed_bdm = self.compute_api._check_and_transform_bdm(
base_options, {}, image_meta, 1, 1, bdms, legacy_bdms)
self.assertThat(expected_bdms,
matchers.DictListMatches(transformed_bdm))
self.context, base_options, {},
image_meta, 1, 1, bdms, legacy_bdms)
for expected, got in zip(expected_bdms, transformed_bdm):
self.assertThat(dict(expected.items()),
matchers.DictMatches(dict(got.items())))
def test_check_and_transform_legacy_bdm_no_image_bdms(self):
legacy_bdms = [
@ -8480,6 +8523,8 @@ class ComputeAPITestCase(BaseTestCase):
expected_bdms = [block_device.BlockDeviceDict.from_legacy(
legacy_bdms[0])]
expected_bdms[0]['boot_index'] = 0
expected_bdms = block_device_obj.block_device_make_list_from_dicts(
self.context, expected_bdms)
self._test_check_and_transform_bdm(legacy_bdms, expected_bdms,
legacy_bdms=True)
@ -8497,6 +8542,8 @@ class ComputeAPITestCase(BaseTestCase):
block_device.BlockDeviceDict.from_legacy(image_bdms[0])]
expected_bdms[0]['boot_index'] = -1
expected_bdms[1]['boot_index'] = 0
expected_bdms = block_device_obj.block_device_make_list_from_dicts(
self.context, expected_bdms)
self._test_check_and_transform_bdm(legacy_bdms, expected_bdms,
image_bdms=image_bdms,
legacy_bdms=True,
@ -8515,6 +8562,8 @@ class ComputeAPITestCase(BaseTestCase):
block_device.BlockDeviceDict.from_legacy(legacy_bdms[0]),
image_bdms[0]]
expected_bdms[0]['boot_index'] = -1
expected_bdms = block_device_obj.block_device_make_list_from_dicts(
self.context, expected_bdms)
self._test_check_and_transform_bdm(legacy_bdms, expected_bdms,
image_bdms=image_bdms,
legacy_bdms=True)
@ -8524,7 +8573,8 @@ class ComputeAPITestCase(BaseTestCase):
'destination_type': 'local',
'image_id': FAKE_IMAGE_REF,
'boot_index': 0})]
expected_bdms = bdms
expected_bdms = block_device_obj.block_device_make_list_from_dicts(
self.context, bdms)
self._test_check_and_transform_bdm(bdms, expected_bdms)
def test_check_and_transform_bdm_image_bdms(self):
@ -8536,6 +8586,8 @@ class ComputeAPITestCase(BaseTestCase):
{'source_type': 'volume', 'destination_type': 'volume',
'volume_id': '33333333-aaaa-bbbb-cccc-444444444444'})]
expected_bdms = bdms + image_bdms
expected_bdms = block_device_obj.block_device_make_list_from_dicts(
self.context, expected_bdms)
self._test_check_and_transform_bdm(bdms, expected_bdms,
image_bdms=image_bdms)
@ -8550,6 +8602,8 @@ class ComputeAPITestCase(BaseTestCase):
expected_bdms = [block_device.BlockDeviceDict.from_legacy(
image_bdms[0])]
expected_bdms[0]['boot_index'] = 0
expected_bdms = block_device_obj.block_device_make_list_from_dicts(
self.context, expected_bdms)
self._test_check_and_transform_bdm(bdms, expected_bdms,
image_bdms=image_bdms,
legacy_image_bdms=True)
@ -8569,30 +8623,26 @@ class ComputeAPITestCase(BaseTestCase):
# We get an image BDM
transformed_bdm = self.compute_api._check_and_transform_bdm(
base_options, {}, {}, 1, 1, fake_legacy_bdms, True)
self.context, base_options, {}, {}, 1, 1, fake_legacy_bdms, True)
self.assertEqual(len(transformed_bdm), 2)
# No image BDM created if image already defines a root BDM
base_options['root_device_name'] = 'vda'
base_options['image_ref'] = None
transformed_bdm = self.compute_api._check_and_transform_bdm(
base_options, {}, image_meta, 1, 1, [], True)
self.context, base_options, {}, image_meta, 1, 1, [], True)
self.assertEqual(len(transformed_bdm), 1)
# No image BDM created
transformed_bdm = self.compute_api._check_and_transform_bdm(
base_options, {}, {}, 1, 1, fake_legacy_bdms, True)
self.context, base_options, {}, {}, 1, 1, fake_legacy_bdms, True)
self.assertEqual(len(transformed_bdm), 1)
# Volumes with multiple instances fails
self.assertRaises(exception.InvalidRequest,
self.compute_api._check_and_transform_bdm,
self.compute_api._check_and_transform_bdm, self.context,
base_options, {}, {}, 1, 2, fake_legacy_bdms, True)
checked_bdm = self.compute_api._check_and_transform_bdm(
base_options, {}, {}, 1, 1, transformed_bdm, True)
self.assertEqual(checked_bdm, transformed_bdm)
# Volume backed so no image_ref in base_options
# v2 bdms contains a root image to volume mapping
# image_meta contains a snapshot as the image
@ -8608,7 +8658,8 @@ class ComputeAPITestCase(BaseTestCase):
'volume_size': 1}]
base_options['image_ref'] = None
transformed_bdm = self.compute_api._check_and_transform_bdm(
base_options, {}, image_meta, 1, 1, fake_v2_bdms, False)
self.context, base_options, {}, image_meta, 1, 1,
fake_v2_bdms, False)
self.assertEqual(len(transformed_bdm), 1)
def test_volume_size(self):

View File

@ -2811,8 +2811,8 @@ class _ComputeAPIUnitTestMixIn(object):
'volume_id': 'volume_id'}]
self.assertRaises(exception.InvalidRequest,
self.compute_api._check_and_transform_bdm,
base_options, instance_type, image_meta, 1, 1,
block_device_mapping, legacy_bdm)
self.context, base_options, instance_type,
image_meta, 1, 1, block_device_mapping, legacy_bdm)
@mock.patch.object(objects.Instance, 'save')
@mock.patch.object(objects.InstanceAction, 'action_start')

View File

@ -181,14 +181,14 @@ class CellsComputeAPITestCase(test_compute.ComputeAPITestCase):
self.assertEqual(migrations, response)
def test_update_block_device_mapping(self):
def test_create_block_device_mapping(self):
instance_type = {'swap': 1, 'ephemeral_gb': 1}
instance = self._create_fake_instance_obj()
bdms = [block_device.BlockDeviceDict({'source_type': 'image',
'destination_type': 'local',
'image_id': 'fake-image',
'boot_index': 0})]
self.compute_api._update_block_device_mapping(
self.compute_api._create_block_device_mapping(
instance_type, instance.uuid, bdms)
bdms = db.block_device_mapping_get_all_by_instance(
self.context, instance['uuid'])