Skip to content

Commit

Permalink
Process image BDM earlier to avoid duplicates
Browse files Browse the repository at this point in the history
If the block device mapping from the image properties are not handled at
the same time as the ones defined from the API, we might make the false
assumption that the instance has no root and failing or, in the case
we're booting from an image that only defines a BDM and has no disk,
creating a local disk BDM as root and ending up with two root devices
which is forbidden.

This patch moves the handling of the image block device mappings to the
same method were we check the ones provided throught the API. This
allows nova to decide wether the instance needs a local disk from an
image if no root device is defined in any of the block device mappings.

Change-Id: Ide95357895ab4dd1338ab5ee3ec25294af1d010b
Closes-Bug: #1246327
(cherry picked from commit 482dfeb)
  • Loading branch information
Xavier Queralt committed Nov 22, 2013
1 parent cad49c3 commit 1d2a0b8
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 20 deletions.
35 changes: 20 additions & 15 deletions nova/compute/api.py
Expand Up @@ -592,15 +592,25 @@ def _check_requested_image(self, context, image_id, image, instance_type):
if int(image.get('min_disk') or 0) > root_gb:
raise exception.InstanceTypeDiskTooSmall()

def _check_and_transform_bdm(self, base_options, min_count, max_count,
block_device_mapping, legacy_bdm):
def _check_and_transform_bdm(self, base_options, 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')
image_ref = base_options.get('image_ref', '')

# Get the block device mappings defined by the image.
image_defined_bdms = \
image_meta.get('properties', {}).get('block_device_mapping', [])

if 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')
block_device_mapping += image_defined_bdms
block_device_mapping = block_device.from_legacy_mapping(
block_device_mapping, base_options.get('image_ref', ''),
root_device_name)
block_device_mapping, image_ref, root_device_name)
elif image_defined_bdms:
# NOTE (ndipanov): For now assume that image mapping is legacy
block_device_mapping += block_device.from_legacy_mapping(
image_defined_bdms, None, root_device_name)

if min_count > 1 or max_count > 1:
if any(map(lambda bdm: bdm['source_type'] == 'volume',
Expand Down Expand Up @@ -861,7 +871,7 @@ def _create_instance(self, context, instance_type,
block_device_mapping, auto_disk_config, reservation_id)

block_device_mapping = self._check_and_transform_bdm(
base_options, min_count, max_count,
base_options, boot_meta, min_count, max_count,
block_device_mapping, legacy_bdm)

instances = self._provision_instances(context, instance_type,
Expand Down Expand Up @@ -1030,15 +1040,10 @@ def _populate_instance_for_bdm(self, context, instance, instance_type,
image_mapping = self._prepare_image_mapping(instance_type,
instance_uuid, image_mapping)

# NOTE (ndipanov): For now assume that image mapping is legacy
image_bdm = block_device.from_legacy_mapping(
image_properties.get('block_device_mapping', []),
None, instance['root_device_name'])

self._validate_bdm(context, instance, instance_type,
block_device_mapping + image_mapping + image_bdm)
block_device_mapping + image_mapping)

for mapping in (image_mapping, image_bdm, block_device_mapping):
for mapping in (image_mapping, block_device_mapping):
if not mapping:
continue
self._update_block_device_mapping(context,
Expand Down
19 changes: 14 additions & 5 deletions nova/tests/compute/test_compute.py
Expand Up @@ -7136,24 +7136,33 @@ def test_check_and_transform_bdm(self):
'volume_id': '33333333-aaaa-bbbb-cccc-333333333333',
'delete_on_termination': False}]

image_meta = {'properties': {'block_device_mapping': [
{'device_name': '/dev/vda',
'snapshot_id': '33333333-aaaa-bbbb-cccc-333333333333'}]}}

# We get an image BDM
transformed_bdm = self.compute_api._check_and_transform_bdm(
base_options, 1, 1, fake_legacy_bdms, True)
base_options, {}, 1, 1, fake_legacy_bdms, True)
self.assertEqual(len(transformed_bdm), 2)

# No image BDM created
# No image BDM created if image already defines a root BDM
base_options['root_device_name'] = 'vda'
transformed_bdm = self.compute_api._check_and_transform_bdm(
base_options, 1, 1, fake_legacy_bdms, True)
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.assertEqual(len(transformed_bdm), 1)

# Volumes with multiple instances fails
self.assertRaises(exception.InvalidRequest,
self.compute_api._check_and_transform_bdm,
base_options, 1, 2, fake_legacy_bdms, True)
base_options, {}, 1, 2, fake_legacy_bdms, True)

checked_bdm = self.compute_api._check_and_transform_bdm(
base_options, 1, 1, transformed_bdm, True)
base_options, {}, 1, 1, transformed_bdm, True)
self.assertEqual(checked_bdm, transformed_bdm)

def test_volume_size(self):
Expand Down

0 comments on commit 1d2a0b8

Please sign in to comment.