diff options
author | jichenjc <jichenjc@cn.ibm.com> | 2015-03-20 08:36:37 +0800 |
---|---|---|
committer | Doug Hellmann <doug@doughellmann.com> | 2015-04-15 19:55:17 +0000 |
commit | 3cff2c673c6cdf487c2a1eb2a5c6c89c6de80d11 (patch) | |
tree | a2377356f028a90e84845dcee1d76b7ff5f6d9eb | |
parent | 77d19b97c69d48ef2512fb3d14b0486ed2137b39 (diff) | |
download | nova-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.py | 8 | ||||
-rw-r--r-- | nova/api/openstack/compute/servers.py | 9 | ||||
-rw-r--r-- | nova/block_device.py | 11 | ||||
-rw-r--r-- | nova/tests/unit/test_block_device.py | 27 |
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): |