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:
parent
c11cd4fa26
commit
220ba7dbbc
|
@ -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 '
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"}
|
||||
|
|
|
@ -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'])
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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'])
|
||||
|
|
Loading…
Reference in New Issue