summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjichenjc <jichenjc@cn.ibm.com>2015-03-20 08:36:37 +0800
committerDoug Hellmann <doug@doughellmann.com>2015-04-15 19:55:17 +0000
commit3cff2c673c6cdf487c2a1eb2a5c6c89c6de80d11 (patch)
treea2377356f028a90e84845dcee1d76b7ff5f6d9eb
parent77d19b97c69d48ef2512fb3d14b0486ed2137b39 (diff)
downloadnova-3cff2c673c6cdf487c2a1eb2a5c6c89c6de80d11.tar.gz
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 (cherry picked from commit cadbcc440a2fcfb8532f38111999a06557fbafc2)
-rw-r--r--nova/api/openstack/compute/plugins/v3/block_device_mapping.py8
-rw-r--r--nova/api/openstack/compute/servers.py9
-rw-r--r--nova/block_device.py11
-rw-r--r--nova/tests/unit/test_block_device.py27
4 files changed, 45 insertions, 10 deletions
diff --git a/nova/api/openstack/compute/plugins/v3/block_device_mapping.py b/nova/api/openstack/compute/plugins/v3/block_device_mapping.py
index c28851e265..4a6f667688 100644
--- a/nova/api/openstack/compute/plugins/v3/block_device_mapping.py
+++ b/nova/api/openstack/compute/plugins/v3/block_device_mapping.py
@@ -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())
diff --git a/nova/api/openstack/compute/servers.py b/nova/api/openstack/compute/servers.py
index 999685ee46..d3d52aedd4 100644
--- a/nova/api/openstack/compute/servers.py
+++ b/nova/api/openstack/compute/servers.py
@@ -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())
@@ -552,7 +553,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
diff --git a/nova/block_device.py b/nova/block_device.py
index 28b496c2c1..d8ae4a6b98 100644
--- a/nova/block_device.py
+++ b/nova/block_device.py
@@ -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)
diff --git a/nova/tests/unit/test_block_device.py b/nova/tests/unit/test_block_device.py
index 6abb58d6fd..7d1bee0bde 100644
--- a/nova/tests/unit/test_block_device.py
+++ b/nova/tests/unit/test_block_device.py
@@ -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):