Changes block_device_mapping extension into v2.1
This patch changes v3 block_device_mapping API to v2.1 and make unittest share between v2 and v2.1 The differences between v2 and v3 are described on the wiki page https://wiki.openstack.org/wiki/NovaAPIv2tov3. Partially implements blueprint v2-on-v3-api Change-Id: I935b336523241a32dbd2bb8b154ce72afefd3aa9
This commit is contained in:
@@ -22,7 +22,7 @@ from nova import block_device
|
||||
from nova import exception
|
||||
|
||||
ALIAS = "os-block-device-mapping"
|
||||
ATTRIBUTE_NAME = "%s:block_device_mapping" % ALIAS
|
||||
ATTRIBUTE_NAME = "block_device_mapping_v2"
|
||||
|
||||
|
||||
class BlockDeviceMapping(extensions.V3APIExtensionBase):
|
||||
|
||||
@@ -545,7 +545,8 @@ class ServersController(wsgi.Controller):
|
||||
exception.SecurityGroupNotFound,
|
||||
exception.PortRequiresFixedIP,
|
||||
exception.NetworkRequiresSubnet,
|
||||
exception.NetworkNotFound) as error:
|
||||
exception.NetworkNotFound,
|
||||
exception.InvalidBDMVolumeNotBootable) as error:
|
||||
raise exc.HTTPBadRequest(explanation=error.format_message())
|
||||
except (exception.PortInUse,
|
||||
exception.NetworkAmbiguous,
|
||||
|
||||
+45
-19
@@ -18,9 +18,11 @@ import mox
|
||||
from oslo.config import cfg
|
||||
from webob import exc
|
||||
|
||||
from nova.api.openstack.compute import extensions
|
||||
from nova.api.openstack.compute import plugins
|
||||
from nova.api.openstack.compute.plugins.v3 import block_device_mapping
|
||||
from nova.api.openstack.compute.plugins.v3 import servers
|
||||
from nova.api.openstack.compute.plugins.v3 import servers as servers_v3
|
||||
from nova.api.openstack.compute import servers as servers_v2
|
||||
from nova import block_device
|
||||
from nova.compute import api as compute_api
|
||||
from nova import exception
|
||||
@@ -33,19 +35,20 @@ from nova.tests import matchers
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
class BlockDeviceMappingTest(test.TestCase):
|
||||
def setUp(self):
|
||||
super(BlockDeviceMappingTest, self).setUp()
|
||||
class BlockDeviceMappingTestV21(test.TestCase):
|
||||
|
||||
def _setup_controller(self):
|
||||
ext_info = plugins.LoadedExtensionInfo()
|
||||
self.controller = servers.ServersController(extension_info=ext_info)
|
||||
|
||||
self.controller = servers_v3.ServersController(extension_info=ext_info)
|
||||
CONF.set_override('extensions_blacklist', 'os-block-device-mapping',
|
||||
'osapi_v3')
|
||||
self.no_volumes_controller = servers.ServersController(
|
||||
extension_info=ext_info)
|
||||
self.no_bdm_v2_controller = servers_v3.ServersController(
|
||||
extension_info=ext_info)
|
||||
CONF.set_override('extensions_blacklist', '', 'osapi_v3')
|
||||
|
||||
def setUp(self):
|
||||
super(BlockDeviceMappingTestV21, self).setUp()
|
||||
self._setup_controller()
|
||||
fake.stub_out_image_service(self.stubs)
|
||||
|
||||
self.bdm = [{
|
||||
@@ -57,7 +60,7 @@ class BlockDeviceMappingTest(test.TestCase):
|
||||
'delete_on_termination': False,
|
||||
}]
|
||||
|
||||
def _test_create(self, params, no_image=False, override_controller=None):
|
||||
def _get_servers_body(self, no_image=False):
|
||||
body = {
|
||||
'server': {
|
||||
'min_count': 2,
|
||||
@@ -70,10 +73,12 @@ class BlockDeviceMappingTest(test.TestCase):
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if no_image:
|
||||
del body['server']['imageRef']
|
||||
return body
|
||||
|
||||
def _test_create(self, params, no_image=False, override_controller=None):
|
||||
body = self._get_servers_body(no_image)
|
||||
body['server'].update(params)
|
||||
|
||||
req = fakes.HTTPRequestV3.blank('/servers')
|
||||
@@ -100,7 +105,7 @@ class BlockDeviceMappingTest(test.TestCase):
|
||||
|
||||
params = {block_device_mapping.ATTRIBUTE_NAME: bdm}
|
||||
self._test_create(params,
|
||||
override_controller=self.no_volumes_controller)
|
||||
override_controller=self.no_bdm_v2_controller)
|
||||
|
||||
def test_create_instance_with_volumes_enabled_no_image(self):
|
||||
"""Test that the create will fail if there is no image
|
||||
@@ -281,14 +286,35 @@ class BlockDeviceMappingTest(test.TestCase):
|
||||
|
||||
@mock.patch('nova.compute.api.API._get_bdm_image_metadata')
|
||||
def test_create_instance_non_bootable_volume_fails(self, fake_bdm_meta):
|
||||
bdm = [{
|
||||
'id': 1,
|
||||
'bootable': False,
|
||||
'volume_id': '1',
|
||||
'status': 'active',
|
||||
'device_name': 'vda',
|
||||
}]
|
||||
params = {'block_device_mapping': bdm}
|
||||
params = {block_device_mapping.ATTRIBUTE_NAME: self.bdm}
|
||||
fake_bdm_meta.side_effect = exception.InvalidBDMVolumeNotBootable(id=1)
|
||||
self.assertRaises(exc.HTTPBadRequest, self._test_create, params,
|
||||
no_image=True)
|
||||
|
||||
|
||||
class BlockDeviceMappingTestV2(BlockDeviceMappingTestV21):
|
||||
|
||||
def _setup_controller(self):
|
||||
self.ext_mgr = extensions.ExtensionManager()
|
||||
self.ext_mgr.extensions = {'os-volumes': 'fake',
|
||||
'os-block-device-mapping-v2-boot': 'fake'}
|
||||
self.controller = servers_v2.Controller(self.ext_mgr)
|
||||
self.ext_mgr_bdm_v2 = extensions.ExtensionManager()
|
||||
self.ext_mgr_bdm_v2.extensions = {'os-volumes': 'fake'}
|
||||
self.no_bdm_v2_controller = servers_v2.Controller(
|
||||
self.ext_mgr_bdm_v2)
|
||||
|
||||
def test_create_instance_with_block_device_mapping_disabled(self):
|
||||
bdm = [{'device_name': 'foo'}]
|
||||
|
||||
old_create = compute_api.API.create
|
||||
|
||||
def create(*args, **kwargs):
|
||||
self.assertIsNone(kwargs['block_device_mapping'], None)
|
||||
return old_create(*args, **kwargs)
|
||||
|
||||
self.stubs.Set(compute_api.API, 'create', create)
|
||||
|
||||
params = {block_device_mapping.ATTRIBUTE_NAME: bdm}
|
||||
self._test_create(params,
|
||||
override_controller=self.no_bdm_v2_controller)
|
||||
@@ -35,7 +35,6 @@ from nova.api.openstack.compute import servers
|
||||
from nova.api.openstack.compute import views
|
||||
from nova.api.openstack import extensions
|
||||
from nova.api.openstack import xmlutil
|
||||
from nova import block_device
|
||||
from nova.compute import api as compute_api
|
||||
from nova.compute import flavors
|
||||
from nova.compute import task_states
|
||||
@@ -2680,41 +2679,6 @@ class ServersControllerCreateTest(test.TestCase):
|
||||
self.mox.ReplayAll()
|
||||
self._test_create_extra(params, no_image=True)
|
||||
|
||||
def test_create_instance_with_bdm_v2_enabled_and_bdms_no_image(self):
|
||||
self.ext_mgr.extensions = {
|
||||
'os-volumes': 'fake',
|
||||
'os-block-device-mapping-v2-boot': 'fake'}
|
||||
bdm_v2 = [{
|
||||
'no_device': None,
|
||||
'source_type': 'volume',
|
||||
'destination_type': 'volume',
|
||||
'uuid': self.volume_id,
|
||||
'device_name': 'vda',
|
||||
'delete_on_termination': False,
|
||||
}]
|
||||
params = {'block_device_mapping_v2': bdm_v2}
|
||||
old_create = compute_api.API.create
|
||||
|
||||
def create(*args, **kwargs):
|
||||
self.assertThat(block_device.BlockDeviceDict(bdm_v2[0]),
|
||||
matchers.DictMatches(
|
||||
kwargs['block_device_mapping'][0]))
|
||||
self.assertNotIn('imageRef', kwargs)
|
||||
return old_create(*args, **kwargs)
|
||||
|
||||
self.mox.StubOutWithMock(compute_api.API, '_validate_bdm')
|
||||
self.mox.StubOutWithMock(compute_api.API, '_get_bdm_image_metadata')
|
||||
|
||||
compute_api.API._validate_bdm(
|
||||
mox.IgnoreArg(), mox.IgnoreArg(),
|
||||
mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(True)
|
||||
compute_api.API._get_bdm_image_metadata(
|
||||
mox.IgnoreArg(), mox.IgnoreArg(), False).AndReturn({})
|
||||
self.mox.ReplayAll()
|
||||
self.stubs.Set(compute_api.API, 'create', create)
|
||||
|
||||
self._test_create_extra(params, no_image=True)
|
||||
|
||||
def test_create_instance_with_volumes_disabled(self):
|
||||
bdm = [{'device_name': 'foo'}]
|
||||
params = {'block_device_mapping': bdm}
|
||||
@@ -2817,7 +2781,7 @@ class ServersControllerCreateTest(test.TestCase):
|
||||
|
||||
def test_create_instance_bdm_api_validation_fails(self):
|
||||
self.ext_mgr.extensions = {'os-volumes': 'fake',
|
||||
'os-block-device-mapping-v2-boot': 'fake'}
|
||||
'os-block-devic-emapping-v2-boot': 'fake'}
|
||||
bdm = {'delete_on_termination': 1,
|
||||
'device_name': 'vda',
|
||||
'source_type': 'volume',
|
||||
@@ -2893,33 +2857,6 @@ class ServersControllerCreateTest(test.TestCase):
|
||||
self.stubs.Set(compute_api.API, '_validate_bdm', _validate_bdm)
|
||||
self._test_create_extra(params)
|
||||
|
||||
def test_create_instance_bdm_v2(self):
|
||||
self.ext_mgr.extensions = {'os-volumes': 'fake',
|
||||
'os-block-device-mapping-v2-boot': 'fake'}
|
||||
bdm_v2 = [{'source_type': 'volume',
|
||||
'device_name': 'fake_dev',
|
||||
'uuid': 'fake_vol'}]
|
||||
bdm_v2_expected = [{'source_type': 'volume',
|
||||
'device_name': 'fake_dev',
|
||||
'volume_id': 'fake_vol'}]
|
||||
params = {'block_device_mapping_v2': bdm_v2}
|
||||
old_create = compute_api.API.create
|
||||
|
||||
def create(*args, **kwargs):
|
||||
self.assertFalse(kwargs['legacy_bdm'])
|
||||
for expected, received in zip(bdm_v2_expected,
|
||||
kwargs['block_device_mapping']):
|
||||
self.assertThat(block_device.BlockDeviceDict(expected),
|
||||
matchers.DictMatches(received))
|
||||
return old_create(*args, **kwargs)
|
||||
|
||||
def _validate_bdm(*args, **kwargs):
|
||||
pass
|
||||
|
||||
self.stubs.Set(compute_api.API, 'create', create)
|
||||
self.stubs.Set(compute_api.API, '_validate_bdm', _validate_bdm)
|
||||
self._test_create_extra(params)
|
||||
|
||||
def test_create_instance_decide_format_legacy(self):
|
||||
self.ext_mgr.extensions = {'os-volumes': 'fake',
|
||||
'os-block-device-mapping-v2-boot': 'fake'}
|
||||
@@ -2947,32 +2884,6 @@ class ServersControllerCreateTest(test.TestCase):
|
||||
params = {'block_device_mapping': bdm}
|
||||
self._test_create_extra(params)
|
||||
|
||||
def test_create_instance_decide_format_new(self):
|
||||
self.ext_mgr.extensions = {'os-volumes': 'fake',
|
||||
'os-block-device-mapping-v2-boot': 'fake'}
|
||||
|
||||
bdm_v2 = [{'source_type': 'volume',
|
||||
'device_name': 'fake_dev',
|
||||
'uuid': 'fake_vol'}]
|
||||
|
||||
old_create = compute_api.API.create
|
||||
|
||||
expected_legacy_flag = False
|
||||
|
||||
def create(*args, **kwargs):
|
||||
self.assertEqual(kwargs['legacy_bdm'], expected_legacy_flag)
|
||||
return old_create(*args, **kwargs)
|
||||
|
||||
def _validate_bdm(*args, **kwargs):
|
||||
pass
|
||||
|
||||
self.stubs.Set(compute_api.API, 'create', create)
|
||||
self.stubs.Set(compute_api.API, '_validate_bdm',
|
||||
_validate_bdm)
|
||||
|
||||
params = {'block_device_mapping_v2': bdm_v2}
|
||||
self._test_create_extra(params)
|
||||
|
||||
def test_create_instance_both_bdm_formats(self):
|
||||
self.ext_mgr.extensions = {'os-volumes': 'fake',
|
||||
'os-block-device-mapping-v2-boot': 'fake'}
|
||||
@@ -2985,21 +2896,6 @@ class ServersControllerCreateTest(test.TestCase):
|
||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||
self._test_create_extra, params)
|
||||
|
||||
def test_create_instance_bdm_v2_validation_error(self):
|
||||
self.ext_mgr.extensions = {'os-volumes': 'fake',
|
||||
'os-block-device-mapping-v2-boot': 'fake'}
|
||||
bdm_v2 = [{'device_name': 'bogus device'}]
|
||||
params = {'block_device_mapping_v2': bdm_v2}
|
||||
|
||||
def _validate(*args, **kwargs):
|
||||
raise exception.InvalidBDMFormat()
|
||||
|
||||
self.stubs.Set(block_device.BlockDeviceDict,
|
||||
'_validate', _validate)
|
||||
|
||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||
self._test_create_extra, params)
|
||||
|
||||
def test_create_instance_with_user_data_enabled(self):
|
||||
self.ext_mgr.extensions = {'os-user-data': 'fake'}
|
||||
user_data = 'fake'
|
||||
|
||||
Reference in New Issue
Block a user