Release bdm constraint source and dest type
https://bugs.launchpad.net/nova/+bug/1377958 fixed a problem that source_type: image, destination_type: local is not supported for boot instance, exception should be raised to reject the param otherwise it will lead to instance become ERROR state. However the fix introduced a problem on nova client https://bugs.launchpad.net/python-novaclient/+bug/1418484 The fix of the bug leads to following command become invalid nova boot test-vm --flavor m1.medium --image centos-vm-32 --nic net-id=c3f40e33-d535-4217-916b-1450b8cd3987 --block-device id=26b7b917-2794-452a-95e5-2efb2ca6e32d,bus=sata,source=volume,bootindex=1 So we need to release the original constraint to allow the above special case pass the validation check then we can revert the nova client exception (https://review.openstack.org/#/c/165932/) This patch checks the boot_index and whether image param is given after we found the bdm has source_type: image, destination_type: local, if this is the special case, then no exception will be raised. Closes-Bug: #1433609 Change-Id: If43faae95169bc3864449a8364975f5c887aac14
This commit is contained in:
parent
37a6c601f3
commit
cadbcc440a
|
@ -47,6 +47,11 @@ class BlockDeviceMapping(extensions.V3APIExtensionBase):
|
|||
# NOTE(gmann): This function is not supposed to use 'body_deprecated_param'
|
||||
# parameter as this is placed to handle scheduler_hint extension for V2.1.
|
||||
def server_create(self, server_dict, create_kwargs, body_deprecated_param):
|
||||
|
||||
# Have to check whether --image is given, see bug 1433609
|
||||
image_href = server_dict.get('imageRef')
|
||||
image_uuid_specified = image_href is not None
|
||||
|
||||
bdm = server_dict.get(ATTRIBUTE_NAME, [])
|
||||
legacy_bdm = server_dict.get(LEGACY_ATTRIBUTE_NAME, [])
|
||||
|
||||
|
@ -57,7 +62,8 @@ class BlockDeviceMapping(extensions.V3APIExtensionBase):
|
|||
|
||||
try:
|
||||
block_device_mapping = [
|
||||
block_device.BlockDeviceDict.from_api(bdm_dict)
|
||||
block_device.BlockDeviceDict.from_api(bdm_dict,
|
||||
image_uuid_specified)
|
||||
for bdm_dict in bdm]
|
||||
except exception.InvalidBDMFormat as e:
|
||||
raise exc.HTTPBadRequest(explanation=e.format_message())
|
||||
|
|
|
@ -383,7 +383,7 @@ class Controller(wsgi.Controller):
|
|||
raise exc.HTTPBadRequest(explanation=expl)
|
||||
return user_data
|
||||
|
||||
def _extract_bdm(self, server_dict):
|
||||
def _extract_bdm(self, server_dict, image_uuid_specified):
|
||||
legacy_bdm = True
|
||||
block_device_mapping = None
|
||||
block_device_mapping_v2 = None
|
||||
|
@ -424,7 +424,8 @@ class Controller(wsgi.Controller):
|
|||
|
||||
try:
|
||||
block_device_mapping_v2 = [
|
||||
block_device.BlockDeviceDict.from_api(bdm_dict)
|
||||
block_device.BlockDeviceDict.from_api(bdm_dict,
|
||||
image_uuid_specified)
|
||||
for bdm_dict in block_device_mapping_v2]
|
||||
except exception.InvalidBDMFormat as e:
|
||||
raise exc.HTTPBadRequest(explanation=e.format_message())
|
||||
|
@ -543,7 +544,9 @@ class Controller(wsgi.Controller):
|
|||
user_data = self._extract(server_dict, 'os-user-data', 'user_data')
|
||||
self._validate_user_data(user_data)
|
||||
|
||||
legacy_bdm, block_device_mapping = self._extract_bdm(server_dict)
|
||||
image_uuid_specified = bool(image_uuid)
|
||||
legacy_bdm, block_device_mapping = self._extract_bdm(server_dict,
|
||||
image_uuid_specified)
|
||||
|
||||
ret_resv_id = False
|
||||
# min_count and max_count are optional. If they exist, they may come
|
||||
|
|
|
@ -171,7 +171,7 @@ class BlockDeviceDict(dict):
|
|||
return cls(new_bdm, non_computable_fields)
|
||||
|
||||
@classmethod
|
||||
def from_api(cls, api_dict):
|
||||
def from_api(cls, api_dict, image_uuid_specified):
|
||||
"""Transform the API format of data to the internally used one.
|
||||
|
||||
Only validate if the source_type field makes sense.
|
||||
|
@ -194,8 +194,13 @@ class BlockDeviceDict(dict):
|
|||
details=_("Missing device UUID."))
|
||||
api_dict[source_type + '_id'] = device_uuid
|
||||
if source_type == 'image' and destination_type == 'local':
|
||||
raise exception.InvalidBDMFormat(
|
||||
details=_("Mapping image to local is not supported."))
|
||||
boot_index = api_dict.get('boot_index', -1)
|
||||
|
||||
# if this bdm is generated from --image ,then
|
||||
# source_type = image and destination_type = local is allowed
|
||||
if not (image_uuid_specified and boot_index == 0):
|
||||
raise exception.InvalidBDMFormat(
|
||||
details=_("Mapping image to local is not supported."))
|
||||
|
||||
api_dict.pop('uuid', None)
|
||||
return cls(api_dict)
|
||||
|
|
|
@ -523,7 +523,7 @@ class TestBlockDeviceDict(test.NoDBTestCase):
|
|||
if new['snapshot_id']:
|
||||
new['volume_id'] = None
|
||||
self.assertThat(
|
||||
block_device.BlockDeviceDict.from_api(api),
|
||||
block_device.BlockDeviceDict.from_api(api, False),
|
||||
matchers.IsSubDictOf(new))
|
||||
|
||||
def test_from_api_invalid_blank_id(self):
|
||||
|
@ -534,7 +534,8 @@ class TestBlockDeviceDict(test.NoDBTestCase):
|
|||
'delete_on_termination': True,
|
||||
'boot_index': -1}
|
||||
self.assertRaises(exception.InvalidBDMFormat,
|
||||
block_device.BlockDeviceDict.from_api, api_dict)
|
||||
block_device.BlockDeviceDict.from_api, api_dict,
|
||||
False)
|
||||
|
||||
def test_from_api_invalid_source_to_local_mapping(self):
|
||||
api_dict = {'id': 1,
|
||||
|
@ -542,7 +543,27 @@ class TestBlockDeviceDict(test.NoDBTestCase):
|
|||
'destination_type': 'local',
|
||||
'uuid': 'fake-volume-id-1'}
|
||||
self.assertRaises(exception.InvalidBDMFormat,
|
||||
block_device.BlockDeviceDict.from_api, api_dict)
|
||||
block_device.BlockDeviceDict.from_api, api_dict,
|
||||
False)
|
||||
|
||||
def test_from_api_valid_source_to_local_mapping(self):
|
||||
api_dict = {'id': 1,
|
||||
'source_type': 'image',
|
||||
'destination_type': 'local',
|
||||
'volume_id': 'fake-volume-id-1',
|
||||
'uuid': 1,
|
||||
'boot_index': 0}
|
||||
|
||||
retexp = block_device.BlockDeviceDict(
|
||||
{'id': 1,
|
||||
'source_type': 'image',
|
||||
'image_id': 1,
|
||||
'destination_type': 'local',
|
||||
'volume_id': 'fake-volume-id-1',
|
||||
'boot_index': 0})
|
||||
self.assertEqual(
|
||||
block_device.BlockDeviceDict.from_api(api_dict, True),
|
||||
retexp)
|
||||
|
||||
def test_legacy(self):
|
||||
for legacy, new in zip(self.legacy_mapping, self.new_mapping):
|
||||
|
|
Loading…
Reference in New Issue