Cells: Add support for global cinder

Implements cinder support for compute cells when cinder is a global
installation.  Adds syncing of the block device mapping table between
child cells and API cells.

Implements blueprint cells-cinder-support

Change-Id: Ife5be9922db0742c8ee4f970517396be86597cce
This commit is contained in:
Chris Behrens 2013-06-03 20:02:21 +00:00
parent 9b5e206027
commit 39e8f5bd3b
12 changed files with 444 additions and 22 deletions

View File

@ -64,7 +64,7 @@ class CellsManager(manager.Manager):
Scheduling requests get passed to the scheduler class.
"""
RPC_API_VERSION = '1.9'
RPC_API_VERSION = '1.10'
def __init__(self, *args, **kwargs):
# Mostly for tests.
@ -390,3 +390,14 @@ class CellsManager(manager.Manager):
def get_capacities(self, ctxt, cell_name):
return self.state_manager.get_capacities(cell_name)
def bdm_update_or_create_at_top(self, ctxt, bdm, create=None):
"""BDM was created/updated in this cell. Tell the API cells."""
self.msg_runner.bdm_update_or_create_at_top(ctxt, bdm, create=create)
def bdm_destroy_at_top(self, ctxt, instance_uuid, device_name=None,
volume_id=None):
"""BDM was destroyed for instance in this cell. Tell the API cells."""
self.msg_runner.bdm_destroy_at_top(ctxt, instance_uuid,
device_name=device_name,
volume_id=volume_id)

View File

@ -848,7 +848,8 @@ class _BroadcastMessageMethods(_BaseMessageMethods):
except exception.NotFound:
# FIXME(comstud): Strange. Need to handle quotas here,
# if we actually want this code to remain..
self.db.instance_create(message.ctxt, instance)
self.db.instance_create(message.ctxt, instance,
legacy=False)
if info_cache:
try:
self.db.instance_info_cache_update(
@ -959,6 +960,60 @@ class _BroadcastMessageMethods(_BaseMessageMethods):
self.consoleauth_rpcapi.delete_tokens_for_instance(message.ctxt,
instance_uuid)
def bdm_update_or_create_at_top(self, message, bdm, create):
"""Create or update a block device mapping in API cells. If
create is True, only try to create. If create is None, try to
update but fall back to create. If create is False, only attempt
to update. This maps to nova-conductor's behavior.
"""
if not self._at_the_top():
return
items_to_remove = ['id']
for key in items_to_remove:
bdm.pop(key, None)
if create is None:
self.db.block_device_mapping_update_or_create(message.ctxt,
bdm,
legacy=False)
return
elif create is True:
self.db.block_device_mapping_create(message.ctxt, bdm,
legacy=False)
return
# Unfortunately this update call wants BDM ID... but we don't know
# what it is in this cell. Search for it.. try matching either
# device_name or volume_id.
dev_name = bdm['device_name']
vol_id = bdm['volume_id']
instance_bdms = self.db.block_device_mapping_get_all_by_instance(
message.ctxt, bdm['instance_uuid'])
for instance_bdm in instance_bdms:
if dev_name and instance_bdm['device_name'] == dev_name:
break
if vol_id and instance_bdm['volume_id'] == vol_id:
break
else:
LOG.warn(_("No match when trying to update BDM: %(bdm)s"),
dict(bdm=bdm))
return
self.db.block_device_mapping_update(message.ctxt,
instance_bdm['id'], bdm,
legacy=False)
def bdm_destroy_at_top(self, message, instance_uuid, device_name,
volume_id):
"""Destroy a block device mapping in API cells by device name
or volume_id. device_name or volume_id can be None, but not both.
"""
if not self._at_the_top():
return
if device_name:
self.db.block_device_mapping_destroy_by_instance_and_device(
message.ctxt, instance_uuid, device_name)
elif volume_id:
self.db.block_device_mapping_destroy_by_instance_and_volume(
message.ctxt, instance_uuid, volume_id)
_CELL_MESSAGE_TYPE_TO_MESSAGE_CLS = {'targeted': _TargetedMessage,
'broadcast': _BroadcastMessage,
@ -1344,6 +1399,25 @@ class MessageRunner(object):
cell_name, need_response=True)
return message.process()
def bdm_update_or_create_at_top(self, ctxt, bdm, create=None):
"""Update/Create a BDM at top level cell."""
message = _BroadcastMessage(self, ctxt,
'bdm_update_or_create_at_top',
dict(bdm=bdm, create=create),
'up', run_locally=False)
message.process()
def bdm_destroy_at_top(self, ctxt, instance_uuid, device_name=None,
volume_id=None):
"""Destroy a BDM at top level cell."""
method_kwargs = dict(instance_uuid=instance_uuid,
device_name=device_name,
volume_id=volume_id)
message = _BroadcastMessage(self, ctxt, 'bdm_destroy_at_top',
method_kwargs,
'up', run_locally=False)
message.process()
@staticmethod
def get_message_types():
return _CELL_MESSAGE_TYPE_TO_MESSAGE_CLS.keys()

View File

@ -26,9 +26,11 @@ from oslo.config import cfg
from nova import exception
from nova.openstack.common import jsonutils
from nova.openstack.common import log as logging
from nova.openstack.common.rpc import proxy as rpc_proxy
LOG = logging.getLogger(__name__)
CONF = cfg.CONF
CONF.import_opt('enable', 'nova.cells.opts', group='cells')
CONF.import_opt('topic', 'nova.cells.opts', group='cells')
@ -52,6 +54,7 @@ class CellsAPI(rpc_proxy.RpcProxy):
1.7 - Adds service_update()
1.8 - Adds build_instances(), deprecates schedule_run_instance()
1.9 - Adds get_capacities()
1.10 - Adds bdm_update_or_create_at_top(), and bdm_destroy_at_top()
'''
BASE_RPC_API_VERSION = '1.0'
@ -298,3 +301,34 @@ class CellsAPI(rpc_proxy.RpcProxy):
return self.call(ctxt,
self.make_msg('get_capacities', cell_name=cell_name),
version='1.9')
def bdm_update_or_create_at_top(self, ctxt, bdm, create=None):
"""Create or update a block device mapping in API cells. If
create is True, only try to create. If create is None, try to
update but fall back to create. If create is False, only attempt
to update. This maps to nova-conductor's behavior.
"""
if not CONF.cells.enable:
return
try:
self.cast(ctxt, self.make_msg('bdm_update_or_create_at_top',
bdm=bdm, create=create),
version='1.10')
except Exception:
LOG.exception(_("Failed to notify cells of BDM update/create."))
def bdm_destroy_at_top(self, ctxt, instance_uuid, device_name=None,
volume_id=None):
"""Broadcast upwards that a block device mapping was destroyed.
One of device_name or volume_id should be specified.
"""
if not CONF.cells.enable:
return
try:
self.cast(ctxt, self.make_msg('bdm_destroy_at_top',
instance_uuid=instance_uuid,
device_name=device_name,
volume_id=volume_id),
version='1.10')
except Exception:
LOG.exception(_("Failed to notify cells of BDM destroy."))

View File

@ -520,8 +520,6 @@ class ComputeCellsAPI(compute_api.API):
"""Attach an existing volume to an existing instance."""
if device and not block_device.match_device(device):
raise exception.InvalidDevicePath(path=device)
device = self.compute_rpcapi.reserve_block_device_name(
context, device=device, instance=instance, volume_id=volume_id)
try:
volume = self.volume_api.get(context, volume_id)
self.volume_api.check_attach(context, volume, instance=instance)
@ -529,7 +527,7 @@ class ComputeCellsAPI(compute_api.API):
with excutils.save_and_reraise_exception():
self.db.block_device_mapping_destroy_by_instance_and_device(
context, instance['uuid'], device)
self._cast_to_cells(context, instance, 'attach_volume',
return self._call_to_cells(context, instance, 'attach_volume',
volume_id, device)
@validate_cell

View File

@ -18,6 +18,7 @@ import copy
from nova.api.ec2 import ec2utils
from nova import block_device
from nova.cells import rpcapi as cells_rpcapi
from nova.compute import api as compute_api
from nova.compute import utils as compute_utils
from nova import exception
@ -78,6 +79,7 @@ class ConductorManager(manager.Manager):
self._compute_api = None
self.compute_task_mgr = ComputeTaskManager()
self.quotas = quota.QUOTAS
self.cells_rpcapi = cells_rpcapi.CellsAPI()
def create_rpc_dispatcher(self, *args, **kwargs):
kwargs['additional_apis'] = [self.compute_task_mgr]
@ -259,11 +261,18 @@ class ConductorManager(manager.Manager):
def block_device_mapping_update_or_create(self, context, values,
create=None):
if create is None:
self.db.block_device_mapping_update_or_create(context, values)
bdm = self.db.block_device_mapping_update_or_create(context,
values)
elif create is True:
self.db.block_device_mapping_create(context, values)
bdm = self.db.block_device_mapping_create(context, values)
else:
self.db.block_device_mapping_update(context, values['id'], values)
bdm = self.db.block_device_mapping_update(context,
values['id'],
values)
# NOTE:comstud): 'bdm' is always in the new format, so we
# account for this in cells/messaging.py
self.cells_rpcapi.bdm_update_or_create_at_top(context, bdm,
create=create)
def block_device_mapping_get_all_by_instance(self, context, instance,
legacy=True):
@ -279,12 +288,36 @@ class ConductorManager(manager.Manager):
if bdms is not None:
for bdm in bdms:
self.db.block_device_mapping_destroy(context, bdm['id'])
# NOTE(comstud): bdm['id'] will be different in API cell,
# so we must try to destroy by device_name or volume_id.
# We need an instance_uuid in order to do this properly,
# too.
# I hope to clean a lot of this up in the object
# implementation.
instance_uuid = (bdm['instance_uuid'] or
(instance and instance['uuid']))
if not instance_uuid:
continue
# Better to be safe than sorry. device_name is not
# NULLable, however it could be an empty string.
if bdm['device_name']:
self.cells_rpcapi.bdm_destroy_at_top(
context, instance_uuid,
device_name=bdm['device_name'])
elif bdm['volume_id']:
self.cells_rpcapi.bdm_destroy_at_top(
context, instance_uuid,
volume_id=bdm['volume_id'])
elif instance is not None and volume_id is not None:
self.db.block_device_mapping_destroy_by_instance_and_volume(
context, instance['uuid'], volume_id)
self.cells_rpcapi.bdm_destroy_at_top(
context, instance['uuid'], volume_id=volume_id)
elif instance is not None and device_name is not None:
self.db.block_device_mapping_destroy_by_instance_and_device(
context, instance['uuid'], device_name)
self.cells_rpcapi.bdm_destroy_at_top(
context, instance['uuid'], device_name=device_name)
else:
# NOTE(danms): This shouldn't happen
raise exception.Invalid(_("Invalid block_device_mapping_destroy"

View File

@ -3139,15 +3139,16 @@ def block_device_mapping_create(context, values, legacy=True):
bdm_ref = models.BlockDeviceMapping()
bdm_ref.update(values)
bdm_ref.save()
return bdm_ref
@require_context
def block_device_mapping_update(context, bdm_id, values, legacy=True):
_scrub_empty_str_values(values, ['volume_size'])
values = _from_legacy_values(values, legacy, allow_updates=True)
_block_device_mapping_get_query(context).\
filter_by(id=bdm_id).\
update(values)
query = _block_device_mapping_get_query(context).filter_by(id=bdm_id)
query.update(values)
return query.first()
def block_device_mapping_update_or_create(context, values, legacy=True):
@ -3163,6 +3164,7 @@ def block_device_mapping_update_or_create(context, values, legacy=True):
bdm_ref = models.BlockDeviceMapping()
bdm_ref.update(values)
bdm_ref.save(session=session)
result = bdm_ref
else:
values = _from_legacy_values(values, legacy, allow_updates=True)
result.update(values)
@ -3185,6 +3187,7 @@ def block_device_mapping_update_or_create(context, values, legacy=True):
models.BlockDeviceMapping.guest_format == None,
models.BlockDeviceMapping.guest_format != 'swap')).
soft_delete())
return result
@require_context

View File

@ -2121,6 +2121,7 @@ class CloudTestCase(test.TestCase):
return [dict(id=1,
source_type='snapshot',
destination_type='volume',
instance_uuid=inst_id,
snapshot_id=snapshots[0],
volume_id=volumes[0],
volume_size=1,

View File

@ -548,3 +548,27 @@ class CellsManagerClassTestCase(test.TestCase):
instance_uuid=instance_uuid, console_port=console_port,
console_type=console_type)
self.assertEqual('fake-response', response)
def test_bdm_update_or_create_at_top(self):
self.mox.StubOutWithMock(self.msg_runner,
'bdm_update_or_create_at_top')
self.msg_runner.bdm_update_or_create_at_top(self.ctxt,
'fake-bdm',
create='foo')
self.mox.ReplayAll()
self.cells_manager.bdm_update_or_create_at_top(self.ctxt,
'fake-bdm',
create='foo')
def test_bdm_destroy_at_top(self):
self.mox.StubOutWithMock(self.msg_runner, 'bdm_destroy_at_top')
self.msg_runner.bdm_destroy_at_top(self.ctxt,
'fake_instance_uuid',
device_name='fake_device_name',
volume_id='fake_volume_id')
self.mox.ReplayAll()
self.cells_manager.bdm_destroy_at_top(self.ctxt,
'fake_instance_uuid',
device_name='fake_device_name',
volume_id='fake_volume_id')

View File

@ -1425,3 +1425,173 @@ class CellsBroadcastMethodsTestCase(test.TestCase):
self.mox.ReplayAll()
self.src_msg_runner.consoleauth_delete_tokens(self.ctxt, fake_uuid)
def test_bdm_update_or_create_with_none_create(self):
fake_bdm = {'id': 'fake_id',
'volume_id': 'fake_volume_id'}
expected_bdm = fake_bdm.copy()
expected_bdm.pop('id')
# Shouldn't be called for these 2 cells
self.mox.StubOutWithMock(self.src_db_inst,
'block_device_mapping_update_or_create')
self.mox.StubOutWithMock(self.mid_db_inst,
'block_device_mapping_update_or_create')
self.mox.StubOutWithMock(self.tgt_db_inst,
'block_device_mapping_update_or_create')
self.tgt_db_inst.block_device_mapping_update_or_create(
self.ctxt, expected_bdm, legacy=False)
self.mox.ReplayAll()
self.src_msg_runner.bdm_update_or_create_at_top(self.ctxt,
fake_bdm,
create=None)
def test_bdm_update_or_create_with_true_create(self):
fake_bdm = {'id': 'fake_id',
'volume_id': 'fake_volume_id'}
expected_bdm = fake_bdm.copy()
expected_bdm.pop('id')
# Shouldn't be called for these 2 cells
self.mox.StubOutWithMock(self.src_db_inst,
'block_device_mapping_create')
self.mox.StubOutWithMock(self.mid_db_inst,
'block_device_mapping_create')
self.mox.StubOutWithMock(self.tgt_db_inst,
'block_device_mapping_create')
self.tgt_db_inst.block_device_mapping_create(
self.ctxt, fake_bdm, legacy=False)
self.mox.ReplayAll()
self.src_msg_runner.bdm_update_or_create_at_top(self.ctxt,
fake_bdm,
create=True)
def test_bdm_update_or_create_with_false_create_vol_id(self):
fake_bdm = {'id': 'fake_id',
'instance_uuid': 'fake_instance_uuid',
'device_name': 'fake_device_name',
'volume_id': 'fake_volume_id'}
expected_bdm = fake_bdm.copy()
expected_bdm.pop('id')
fake_inst_bdms = [{'id': 1,
'volume_id': 'not-a-match',
'device_name': 'not-a-match'},
{'id': 2,
'volume_id': 'fake_volume_id',
'device_name': 'not-a-match'},
{'id': 3,
'volume_id': 'not-a-match',
'device_name': 'not-a-match'}]
# Shouldn't be called for these 2 cells
self.mox.StubOutWithMock(self.src_db_inst,
'block_device_mapping_update')
self.mox.StubOutWithMock(self.mid_db_inst,
'block_device_mapping_update')
self.mox.StubOutWithMock(self.tgt_db_inst,
'block_device_mapping_get_all_by_instance')
self.mox.StubOutWithMock(self.tgt_db_inst,
'block_device_mapping_update')
self.tgt_db_inst.block_device_mapping_get_all_by_instance(
self.ctxt, 'fake_instance_uuid').AndReturn(
fake_inst_bdms)
# Should try to update ID 2.
self.tgt_db_inst.block_device_mapping_update(
self.ctxt, 2, expected_bdm, legacy=False)
self.mox.ReplayAll()
self.src_msg_runner.bdm_update_or_create_at_top(self.ctxt,
fake_bdm,
create=False)
def test_bdm_update_or_create_with_false_create_dev_name(self):
fake_bdm = {'id': 'fake_id',
'instance_uuid': 'fake_instance_uuid',
'device_name': 'fake_device_name',
'volume_id': 'fake_volume_id'}
expected_bdm = fake_bdm.copy()
expected_bdm.pop('id')
fake_inst_bdms = [{'id': 1,
'volume_id': 'not-a-match',
'device_name': 'not-a-match'},
{'id': 2,
'volume_id': 'not-a-match',
'device_name': 'fake_device_name'},
{'id': 3,
'volume_id': 'not-a-match',
'device_name': 'not-a-match'}]
# Shouldn't be called for these 2 cells
self.mox.StubOutWithMock(self.src_db_inst,
'block_device_mapping_update')
self.mox.StubOutWithMock(self.mid_db_inst,
'block_device_mapping_update')
self.mox.StubOutWithMock(self.tgt_db_inst,
'block_device_mapping_get_all_by_instance')
self.mox.StubOutWithMock(self.tgt_db_inst,
'block_device_mapping_update')
self.tgt_db_inst.block_device_mapping_get_all_by_instance(
self.ctxt, 'fake_instance_uuid').AndReturn(
fake_inst_bdms)
# Should try to update ID 2.
self.tgt_db_inst.block_device_mapping_update(
self.ctxt, 2, expected_bdm, legacy=False)
self.mox.ReplayAll()
self.src_msg_runner.bdm_update_or_create_at_top(self.ctxt,
fake_bdm,
create=False)
def test_bdm_destroy_by_volume(self):
fake_instance_uuid = 'fake-instance-uuid'
fake_volume_id = 'fake-volume-name'
# Shouldn't be called for these 2 cells
self.mox.StubOutWithMock(self.src_db_inst,
'block_device_mapping_destroy_by_instance_and_volume')
self.mox.StubOutWithMock(self.mid_db_inst,
'block_device_mapping_destroy_by_instance_and_volume')
self.mox.StubOutWithMock(self.tgt_db_inst,
'block_device_mapping_destroy_by_instance_and_volume')
self.tgt_db_inst.block_device_mapping_destroy_by_instance_and_volume(
self.ctxt, fake_instance_uuid, fake_volume_id)
self.mox.ReplayAll()
self.src_msg_runner.bdm_destroy_at_top(self.ctxt, fake_instance_uuid,
volume_id=fake_volume_id)
def test_bdm_destroy_by_device(self):
fake_instance_uuid = 'fake-instance-uuid'
fake_device_name = 'fake-device-name'
# Shouldn't be called for these 2 cells
self.mox.StubOutWithMock(self.src_db_inst,
'block_device_mapping_destroy_by_instance_and_device')
self.mox.StubOutWithMock(self.mid_db_inst,
'block_device_mapping_destroy_by_instance_and_device')
self.mox.StubOutWithMock(self.tgt_db_inst,
'block_device_mapping_destroy_by_instance_and_device')
self.tgt_db_inst.block_device_mapping_destroy_by_instance_and_device(
self.ctxt, fake_instance_uuid, fake_device_name)
self.mox.ReplayAll()
self.src_msg_runner.bdm_destroy_at_top(self.ctxt, fake_instance_uuid,
device_name=fake_device_name)

View File

@ -422,3 +422,29 @@ class CellsAPITestCase(test.TestCase):
self._check_result(call_info, 'validate_console_port',
expected_args, version='1.6')
self.assertEqual(result, 'fake_response')
def test_bdm_update_or_create_at_top(self):
fake_bdm = {'id': 2, 'other': 'meow'}
call_info = self._stub_rpc_method('cast', None)
self.cells_rpcapi.bdm_update_or_create_at_top(
self.fake_context, fake_bdm, create='fake-create')
expected_args = {'bdm': fake_bdm, 'create': 'fake-create'}
self._check_result(call_info, 'bdm_update_or_create_at_top',
expected_args, version='1.10')
def test_bdm_destroy_at_top(self):
call_info = self._stub_rpc_method('cast', None)
self.cells_rpcapi.bdm_destroy_at_top(self.fake_context,
'fake-uuid',
device_name='fake-device',
volume_id='fake-vol')
expected_args = {'instance_uuid': 'fake-uuid',
'device_name': 'fake-device',
'volume_id': 'fake-vol'}
self._check_result(call_info, 'bdm_destroy_at_top',
expected_args, version='1.10')

View File

@ -632,13 +632,28 @@ class ConductorTestCase(_BaseTestCase, test.TestCase):
self.conductor_manager = self.conductor
def test_block_device_mapping_update_or_create(self):
fake_bdm = {'id': 'fake-id'}
fake_bdm = {'id': 'fake-id', 'device_name': 'foo'}
fake_bdm2 = {'id': 'fake-id', 'device_name': 'foo2'}
cells_rpcapi = self.conductor.cells_rpcapi
self.mox.StubOutWithMock(db, 'block_device_mapping_create')
self.mox.StubOutWithMock(db, 'block_device_mapping_update')
self.mox.StubOutWithMock(db, 'block_device_mapping_update_or_create')
db.block_device_mapping_create(self.context, fake_bdm)
db.block_device_mapping_update(self.context, fake_bdm['id'], fake_bdm)
db.block_device_mapping_update_or_create(self.context, fake_bdm)
self.mox.StubOutWithMock(cells_rpcapi,
'bdm_update_or_create_at_top')
db.block_device_mapping_create(self.context,
fake_bdm).AndReturn(fake_bdm2)
cells_rpcapi.bdm_update_or_create_at_top(self.context, fake_bdm2,
create=True)
db.block_device_mapping_update(self.context, fake_bdm['id'],
fake_bdm).AndReturn(fake_bdm2)
cells_rpcapi.bdm_update_or_create_at_top(self.context,
fake_bdm2,
create=False)
db.block_device_mapping_update_or_create(
self.context, fake_bdm).AndReturn(fake_bdm2)
cells_rpcapi.bdm_update_or_create_at_top(self.context,
fake_bdm2,
create=None)
self.mox.ReplayAll()
self.conductor.block_device_mapping_update_or_create(self.context,
fake_bdm,
@ -650,22 +665,44 @@ class ConductorTestCase(_BaseTestCase, test.TestCase):
fake_bdm)
def test_block_device_mapping_destroy(self):
fake_bdm = {'id': 'fake-bdm'}
fake_bdm2 = {'id': 'fake-bdm-2'}
fake_bdm = {'id': 'fake-bdm',
'instance_uuid': 'fake-uuid',
'device_name': 'fake-device1',
'volume_id': 'fake-vol-id1'}
fake_bdm2 = {'id': 'fake-bdm-2',
'instance_uuid': 'fake-uuid2',
'device_name': '',
'volume_id': 'fake-vol-id2'}
fake_inst = {'uuid': 'fake-uuid'}
cells_rpcapi = self.conductor.cells_rpcapi
self.mox.StubOutWithMock(db, 'block_device_mapping_destroy')
self.mox.StubOutWithMock(
db, 'block_device_mapping_destroy_by_instance_and_device')
self.mox.StubOutWithMock(
db, 'block_device_mapping_destroy_by_instance_and_volume')
self.mox.StubOutWithMock(cells_rpcapi, 'bdm_destroy_at_top')
db.block_device_mapping_destroy(self.context, 'fake-bdm')
cells_rpcapi.bdm_destroy_at_top(self.context,
fake_bdm['instance_uuid'],
device_name=fake_bdm['device_name'])
db.block_device_mapping_destroy(self.context, 'fake-bdm-2')
cells_rpcapi.bdm_destroy_at_top(self.context,
fake_bdm2['instance_uuid'],
volume_id=fake_bdm2['volume_id'])
db.block_device_mapping_destroy_by_instance_and_device(self.context,
'fake-uuid',
'fake-device')
cells_rpcapi.bdm_destroy_at_top(self.context, fake_inst['uuid'],
device_name='fake-device')
db.block_device_mapping_destroy_by_instance_and_volume(self.context,
'fake-uuid',
'fake-volume')
cells_rpcapi.bdm_destroy_at_top(self.context, fake_inst['uuid'],
volume_id='fake-volume')
self.mox.ReplayAll()
self.conductor.block_device_mapping_destroy(self.context,
[fake_bdm,
@ -810,8 +847,12 @@ class ConductorRPCAPITestCase(_BaseTestCase, test.TestCase):
fake_bdm)
def test_block_device_mapping_destroy(self):
fake_bdm = {'id': 'fake-bdm'}
fake_bdm = {'id': 'fake-bdm',
'instance_uuid': 'fake-uuid',
'device_name': 'fake-device1',
'volume_id': 'fake-vol-id1'}
fake_inst = {'uuid': 'fake-uuid'}
self.mox.StubOutWithMock(db, 'block_device_mapping_destroy')
self.mox.StubOutWithMock(
db, 'block_device_mapping_destroy_by_instance_and_device')
@ -961,8 +1002,12 @@ class ConductorAPITestCase(_BaseTestCase, test.TestCase):
'fake-bdm')
def test_block_device_mapping_destroy(self):
fake_bdm = {'id': 'fake-bdm'}
fake_bdm = {'id': 'fake-bdm',
'instance_uuid': 'fake-uuid',
'device_name': 'fake-device1',
'volume_id': 'fake-vol-id1'}
fake_inst = {'uuid': 'fake-uuid'}
self.mox.StubOutWithMock(db, 'block_device_mapping_destroy')
self.mox.StubOutWithMock(
db, 'block_device_mapping_destroy_by_instance_and_device')

View File

@ -4039,12 +4039,15 @@ class BlockDeviceMappingTestCase(test.TestCase):
def test_block_device_mapping_update(self):
bdm = self._create_bdm({})
db.block_device_mapping_update(self.ctxt, bdm['id'],
{'destination_type': 'moon'},
legacy=False)
result = db.block_device_mapping_update(
self.ctxt, bdm['id'], {'destination_type': 'moon'},
legacy=False)
uuid = bdm['instance_uuid']
bdm_real = db.block_device_mapping_get_all_by_instance(self.ctxt, uuid)
self.assertEqual(bdm_real[0]['destination_type'], 'moon')
# Also make sure the update call returned correct data
self.assertEqual(dict(bdm_real[0].iteritems()),
dict(result.iteritems()))
def test_block_device_mapping_update_or_create(self):
values = {