diff options
author | Jenkins <jenkins@review.openstack.org> | 2015-04-21 10:49:53 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2015-04-21 10:49:53 +0000 |
commit | 290839b853f58e515dc07c77f03b5ebd1502f57b (patch) | |
tree | 166edac046fa124e4f44e0d7fb2c3fa8662b6226 | |
parent | 916ce6f6efe46964f4d9afafd8bedb0cc2779183 (diff) | |
parent | 3cff2c673c6cdf487c2a1eb2a5c6c89c6de80d11 (diff) | |
download | nova-290839b853f58e515dc07c77f03b5ebd1502f57b.tar.gz |
Merge "Release bdm constraint source and dest type" into stable/kilo
-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): |