Merge "Make _parse_block_device_mapping to return only passed attributes"

This commit is contained in:
Jenkins 2015-07-20 17:26:21 +00:00 committed by Gerrit Code Review
commit 476e899552
4 changed files with 107 additions and 38 deletions

View File

@ -189,12 +189,12 @@ def register_image(context, name=None, image_location=None,
if block_device_mapping:
mappings = instance_api._parse_block_device_mapping(
context, block_device_mapping)
# NOTE(andrey-mp): image BDM requires resource_id instead of 'uuid'
# TODO(ft): merge with image manifets's virtual device mappings
short_root_device_name = (
ec2utils.block_device_strip_dev(root_device_name))
for bdm in mappings:
uuid = bdm.pop('uuid', None)
if uuid:
resource = bdm['source_type'] + '_id'
bdm[resource] = uuid
instance_api._populate_parsed_bdm_parameter(bdm,
short_root_device_name)
properties['bdm_v2'] = True
properties['block_device_mapping'] = json.dumps(mappings)
if architecture is not None:

View File

@ -110,7 +110,7 @@ def run_instances(context, image_id, min_count, max_count,
nova = clients.nova(context)
os_flavor = _get_os_flavor(instance_type, nova)
bdm = _parse_block_device_mapping(context, block_device_mapping)
bdm = _build_block_device_mapping(context, block_device_mapping, os_image)
availability_zone = (placement or {}).get('availability_zone')
if user_data:
user_data = base64.b64decode(user_data)
@ -887,30 +887,28 @@ def _parse_image_parameters(context, image_id, kernel_id, ramdisk_id):
def _parse_block_device_mapping(context, block_device_mapping):
# TODO(ft): check block_device_mapping structure
# TODO(ft): support virtual devices
# TODO(ft): support no_device
bdms = []
for args_bd in (block_device_mapping or []):
bdm = {
'device_name': args_bd['device_name'],
'destination_type': 'volume',
'boot_index': -1,
'source_type': 'blank',
'delete_on_termination': True
}
ebs = args_bd.get('ebs')
if ebs:
bdm['delete_on_termination'] = ebs.get('delete_on_termination',
True)
ec2_id = ebs.get('snapshot_id')
if ec2_id:
if ec2_id.startswith('snap-'):
bdm['source_type'] = 'snapshot'
snapshot = ec2utils.get_db_item(context, ec2_id)
bdm['uuid'] = snapshot['os_id']
bdm['snapshot_id'] = snapshot['os_id']
# NOTE(ft): OpenStack extension, AWS incompatibility
elif ec2_id.startswith('vol-'):
bdm['source_type'] = 'volume'
volume = ec2utils.get_db_item(context, ec2_id)
bdm['uuid'] = volume['os_id']
bdm['volume_id'] = volume['os_id']
else:
# NOTE(ft): AWS returns undocumented
# InvalidSnapshotID.NotFound
@ -918,12 +916,42 @@ def _parse_block_device_mapping(context, block_device_mapping):
snapshot_id=ec2_id)
if 'volume_size' in ebs:
bdm['volume_size'] = ebs['volume_size']
if 'delete_on_termination' in ebs:
bdm['delete_on_termination'] = ebs['delete_on_termination']
bdms.append(bdm)
return bdms
def _build_block_device_mapping(context, block_device_mapping, os_image):
mappings = _parse_block_device_mapping(context, block_device_mapping)
properties = ec2utils.deserialize_os_image_properties(os_image)
root_device_name = (
ec2utils.block_device_properties_root_device_name(properties))
short_root_device_name = ec2utils.block_device_strip_dev(root_device_name)
result = []
for bdm in mappings:
_populate_parsed_bdm_parameter(bdm, short_root_device_name)
source_type = bdm.get('source_type')
if source_type:
uuid = bdm.pop('_'.join([source_type, 'id']), None)
if uuid:
bdm['uuid'] = uuid
result.append(bdm)
return result
def _populate_parsed_bdm_parameter(bdm, short_root_device_name):
bdm.setdefault('delete_on_termination', True)
bdm.setdefault('source_type', 'blank')
if (short_root_device_name ==
ec2utils.block_device_strip_dev(bdm['device_name'])):
bdm['boot_index'] = 0
else:
bdm['boot_index'] = -1
def _format_group_set(context, os_security_groups, groups):
if not os_security_groups:
return None

View File

@ -196,7 +196,10 @@ class ImageTestCase(base.ApiTestCase):
'KernelId': fakes.ID_EC2_IMAGE_AKI_1,
'RamdiskId': fakes.ID_EC2_IMAGE_ARI_1,
'BlockDeviceMapping.1.DeviceName': fakes.ROOT_DEVICE_NAME_IMAGE_2,
'BlockDeviceMapping.1.Ebs.SnapshotId': fakes.ID_EC2_SNAPSHOT_1})
'BlockDeviceMapping.1.Ebs.SnapshotId': fakes.ID_EC2_SNAPSHOT_1,
'BlockDeviceMapping.2.DeviceName': '/dev/vdf',
'BlockDeviceMapping.2.Ebs.VolumeSize': '100',
'BlockDeviceMapping.2.Ebs.DeleteOnTermination': 'False'})
self.assertThat(resp, matchers.DictMatches(
{'imageId': fakes.ID_EC2_IMAGE_2}))
self.db_api.add_item.assert_called_once_with(
@ -211,7 +214,7 @@ class ImageTestCase(base.ApiTestCase):
self.glance.images.create.call_args[1]['properties'],
dict)
bdm = self.glance.images.create.call_args[1]['properties'].pop(
'block_device_mapping', None)
'block_device_mapping', 'null')
self.assertEqual(
{'is_public': False,
'size': 0,
@ -222,12 +225,18 @@ class ImageTestCase(base.ApiTestCase):
'ramdisk_id': fakes.ID_OS_IMAGE_ARI_1,
'bdm_v2': True}},
self.glance.images.create.call_args[1])
self.assertEqual([{'boot_index': -1,
self.assertEqual([{'boot_index': 0,
'delete_on_termination': True,
'destination_type': 'volume',
'device_name': fakes.ROOT_DEVICE_NAME_IMAGE_2,
'source_type': 'snapshot',
'snapshot_id': fakes.ID_OS_SNAPSHOT_1}],
'snapshot_id': fakes.ID_OS_SNAPSHOT_1},
{'boot_index': -1,
'delete_on_termination': False,
'destination_type': 'volume',
'device_name': '/dev/vdf',
'source_type': 'blank',
'volume_size': 100}],
json.loads(bdm))
get_os_image.assert_has_calls(
[mock.call(mock.ANY, fakes.ID_EC2_IMAGE_AKI_1),

View File

@ -318,7 +318,7 @@ class InstanceTestCase(base.ApiTestCase):
fakes.ID_OS_IMAGE_ARI_1: fakes.OSImage(fakes.OS_IMAGE_ARI_1)}))
get_ec2_classic_os_network.return_value = {'id': fakes.random_os_id()}
user_data = base64.b64decode(fakes.USER_DATA_INSTANCE_2)
parse_block_device_mapping.return_value = 'fake_bdm'
parse_block_device_mapping.return_value = []
def do_check(engine, extra_kwargs={}, extra_db_instance={}):
instance_api.instance_engine = engine
@ -347,7 +347,7 @@ class InstanceTestCase(base.ApiTestCase):
mock.ANY, mock.ANY, mock.ANY, min_count=1, max_count=1,
userdata=user_data, kernel_id=fakes.ID_OS_IMAGE_AKI_1,
ramdisk_id=fakes.ID_OS_IMAGE_ARI_1, key_name=None,
block_device_mapping_v2='fake_bdm',
block_device_mapping_v2=[],
availability_zone='fake_zone', security_groups=['default'],
**extra_kwargs)
self.nova.servers.reset_mock()
@ -1434,40 +1434,72 @@ class InstancePrivateTestCase(test_base.BaseTestCase):
{'device_name': '/dev/sdb1',
'ebs': {'volume_size': 55}}])
expected = [{'boot_index': -1,
'uuid': fakes.ID_OS_SNAPSHOT_1,
expected = [{'snapshot_id': fakes.ID_OS_SNAPSHOT_1,
'device_name': '/dev/vdf',
'source_type': 'snapshot',
'destination_type': 'volume',
'delete_on_termination': True},
{'boot_index': -1,
'uuid': fakes.ID_OS_SNAPSHOT_2,
'destination_type': 'volume'},
{'snapshot_id': fakes.ID_OS_SNAPSHOT_2,
'volume_size': 111,
'device_name': '/dev/vdg',
'source_type': 'snapshot',
'destination_type': 'volume',
'delete_on_termination': False},
{'boot_index': -1,
'uuid': fakes.ID_OS_VOLUME_1,
{'volume_id': fakes.ID_OS_VOLUME_1,
'device_name': '/dev/vdh',
'source_type': 'volume',
'destination_type': 'volume',
'delete_on_termination': True},
{'boot_index': -1,
'uuid': fakes.ID_OS_VOLUME_2,
'destination_type': 'volume'},
{'volume_id': fakes.ID_OS_VOLUME_2,
'device_name': '/dev/vdi',
'source_type': 'volume',
'destination_type': 'volume',
'delete_on_termination': True},
{'boot_index': -1,
'volume_size': 55,
{'volume_size': 55,
'device_name': '/dev/sdb1',
'source_type': 'blank',
'destination_type': 'volume',
'delete_on_termination': True}]
'destination_type': 'volume'}]
self.assertThat(expected, matchers.ListMatches(res,
orderless_lists=True))
self.assertThat(expected,
matchers.ListMatches(res, orderless_lists=True),
verbose=True)
@mock.patch('ec2api.db.api.IMPL')
def test_build_block_device_mapping(self, db_api):
fake_context = mock.Mock(service_catalog=[{'type': 'fake'}])
db_api.get_item_by_id.side_effect = tools.get_db_api_get_item_by_id(
fakes.DB_SNAPSHOT_1, fakes.DB_VOLUME_1)
bdms = [
{'device_name': '/dev/sda1',
'ebs': {'snapshot_id': fakes.ID_EC2_SNAPSHOT_1}},
{'device_name': '/dev/vdb',
'ebs': {'snapshot_id': fakes.ID_EC2_VOLUME_1,
'delete_on_termination': False}},
{'device_name': 'vdc',
'ebs': {'volume_size': 100}},
]
expected = [
{'device_name': '/dev/sda1',
'source_type': 'snapshot',
'destination_type': 'volume',
'uuid': fakes.ID_OS_SNAPSHOT_1,
'delete_on_termination': True,
'boot_index': 0},
{'device_name': '/dev/vdb',
'source_type': 'volume',
'destination_type': 'volume',
'uuid': fakes.ID_OS_VOLUME_1,
'delete_on_termination': False,
'boot_index': -1},
{'device_name': 'vdc',
'source_type': 'blank',
'destination_type': 'volume',
'volume_size': 100,
'delete_on_termination': True,
'boot_index': -1},
]
result = instance_api._build_block_device_mapping(
fake_context, bdms, fakes.OSImage(fakes.OS_IMAGE_1))
self.assertEqual(expected, result)
@mock.patch('cinderclient.client.Client')
@mock.patch('novaclient.client.Client')