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:
parent
9b5e206027
commit
39e8f5bd3b
|
@ -64,7 +64,7 @@ class CellsManager(manager.Manager):
|
||||||
|
|
||||||
Scheduling requests get passed to the scheduler class.
|
Scheduling requests get passed to the scheduler class.
|
||||||
"""
|
"""
|
||||||
RPC_API_VERSION = '1.9'
|
RPC_API_VERSION = '1.10'
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
# Mostly for tests.
|
# Mostly for tests.
|
||||||
|
@ -390,3 +390,14 @@ class CellsManager(manager.Manager):
|
||||||
|
|
||||||
def get_capacities(self, ctxt, cell_name):
|
def get_capacities(self, ctxt, cell_name):
|
||||||
return self.state_manager.get_capacities(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)
|
||||||
|
|
|
@ -848,7 +848,8 @@ class _BroadcastMessageMethods(_BaseMessageMethods):
|
||||||
except exception.NotFound:
|
except exception.NotFound:
|
||||||
# FIXME(comstud): Strange. Need to handle quotas here,
|
# FIXME(comstud): Strange. Need to handle quotas here,
|
||||||
# if we actually want this code to remain..
|
# 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:
|
if info_cache:
|
||||||
try:
|
try:
|
||||||
self.db.instance_info_cache_update(
|
self.db.instance_info_cache_update(
|
||||||
|
@ -959,6 +960,60 @@ class _BroadcastMessageMethods(_BaseMessageMethods):
|
||||||
self.consoleauth_rpcapi.delete_tokens_for_instance(message.ctxt,
|
self.consoleauth_rpcapi.delete_tokens_for_instance(message.ctxt,
|
||||||
instance_uuid)
|
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,
|
_CELL_MESSAGE_TYPE_TO_MESSAGE_CLS = {'targeted': _TargetedMessage,
|
||||||
'broadcast': _BroadcastMessage,
|
'broadcast': _BroadcastMessage,
|
||||||
|
@ -1344,6 +1399,25 @@ class MessageRunner(object):
|
||||||
cell_name, need_response=True)
|
cell_name, need_response=True)
|
||||||
return message.process()
|
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
|
@staticmethod
|
||||||
def get_message_types():
|
def get_message_types():
|
||||||
return _CELL_MESSAGE_TYPE_TO_MESSAGE_CLS.keys()
|
return _CELL_MESSAGE_TYPE_TO_MESSAGE_CLS.keys()
|
||||||
|
|
|
@ -26,9 +26,11 @@ from oslo.config import cfg
|
||||||
|
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova.openstack.common import jsonutils
|
from nova.openstack.common import jsonutils
|
||||||
|
from nova.openstack.common import log as logging
|
||||||
from nova.openstack.common.rpc import proxy as rpc_proxy
|
from nova.openstack.common.rpc import proxy as rpc_proxy
|
||||||
|
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
CONF.import_opt('enable', 'nova.cells.opts', group='cells')
|
CONF.import_opt('enable', 'nova.cells.opts', group='cells')
|
||||||
CONF.import_opt('topic', '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.7 - Adds service_update()
|
||||||
1.8 - Adds build_instances(), deprecates schedule_run_instance()
|
1.8 - Adds build_instances(), deprecates schedule_run_instance()
|
||||||
1.9 - Adds get_capacities()
|
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'
|
BASE_RPC_API_VERSION = '1.0'
|
||||||
|
|
||||||
|
@ -298,3 +301,34 @@ class CellsAPI(rpc_proxy.RpcProxy):
|
||||||
return self.call(ctxt,
|
return self.call(ctxt,
|
||||||
self.make_msg('get_capacities', cell_name=cell_name),
|
self.make_msg('get_capacities', cell_name=cell_name),
|
||||||
version='1.9')
|
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."))
|
||||||
|
|
|
@ -520,8 +520,6 @@ class ComputeCellsAPI(compute_api.API):
|
||||||
"""Attach an existing volume to an existing instance."""
|
"""Attach an existing volume to an existing instance."""
|
||||||
if device and not block_device.match_device(device):
|
if device and not block_device.match_device(device):
|
||||||
raise exception.InvalidDevicePath(path=device)
|
raise exception.InvalidDevicePath(path=device)
|
||||||
device = self.compute_rpcapi.reserve_block_device_name(
|
|
||||||
context, device=device, instance=instance, volume_id=volume_id)
|
|
||||||
try:
|
try:
|
||||||
volume = self.volume_api.get(context, volume_id)
|
volume = self.volume_api.get(context, volume_id)
|
||||||
self.volume_api.check_attach(context, volume, instance=instance)
|
self.volume_api.check_attach(context, volume, instance=instance)
|
||||||
|
@ -529,7 +527,7 @@ class ComputeCellsAPI(compute_api.API):
|
||||||
with excutils.save_and_reraise_exception():
|
with excutils.save_and_reraise_exception():
|
||||||
self.db.block_device_mapping_destroy_by_instance_and_device(
|
self.db.block_device_mapping_destroy_by_instance_and_device(
|
||||||
context, instance['uuid'], 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)
|
volume_id, device)
|
||||||
|
|
||||||
@validate_cell
|
@validate_cell
|
||||||
|
|
|
@ -18,6 +18,7 @@ import copy
|
||||||
|
|
||||||
from nova.api.ec2 import ec2utils
|
from nova.api.ec2 import ec2utils
|
||||||
from nova import block_device
|
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 api as compute_api
|
||||||
from nova.compute import utils as compute_utils
|
from nova.compute import utils as compute_utils
|
||||||
from nova import exception
|
from nova import exception
|
||||||
|
@ -78,6 +79,7 @@ class ConductorManager(manager.Manager):
|
||||||
self._compute_api = None
|
self._compute_api = None
|
||||||
self.compute_task_mgr = ComputeTaskManager()
|
self.compute_task_mgr = ComputeTaskManager()
|
||||||
self.quotas = quota.QUOTAS
|
self.quotas = quota.QUOTAS
|
||||||
|
self.cells_rpcapi = cells_rpcapi.CellsAPI()
|
||||||
|
|
||||||
def create_rpc_dispatcher(self, *args, **kwargs):
|
def create_rpc_dispatcher(self, *args, **kwargs):
|
||||||
kwargs['additional_apis'] = [self.compute_task_mgr]
|
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,
|
def block_device_mapping_update_or_create(self, context, values,
|
||||||
create=None):
|
create=None):
|
||||||
if create is 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:
|
elif create is True:
|
||||||
self.db.block_device_mapping_create(context, values)
|
bdm = self.db.block_device_mapping_create(context, values)
|
||||||
else:
|
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,
|
def block_device_mapping_get_all_by_instance(self, context, instance,
|
||||||
legacy=True):
|
legacy=True):
|
||||||
|
@ -279,12 +288,36 @@ class ConductorManager(manager.Manager):
|
||||||
if bdms is not None:
|
if bdms is not None:
|
||||||
for bdm in bdms:
|
for bdm in bdms:
|
||||||
self.db.block_device_mapping_destroy(context, bdm['id'])
|
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:
|
elif instance is not None and volume_id is not None:
|
||||||
self.db.block_device_mapping_destroy_by_instance_and_volume(
|
self.db.block_device_mapping_destroy_by_instance_and_volume(
|
||||||
context, instance['uuid'], volume_id)
|
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:
|
elif instance is not None and device_name is not None:
|
||||||
self.db.block_device_mapping_destroy_by_instance_and_device(
|
self.db.block_device_mapping_destroy_by_instance_and_device(
|
||||||
context, instance['uuid'], device_name)
|
context, instance['uuid'], device_name)
|
||||||
|
self.cells_rpcapi.bdm_destroy_at_top(
|
||||||
|
context, instance['uuid'], device_name=device_name)
|
||||||
else:
|
else:
|
||||||
# NOTE(danms): This shouldn't happen
|
# NOTE(danms): This shouldn't happen
|
||||||
raise exception.Invalid(_("Invalid block_device_mapping_destroy"
|
raise exception.Invalid(_("Invalid block_device_mapping_destroy"
|
||||||
|
|
|
@ -3139,15 +3139,16 @@ def block_device_mapping_create(context, values, legacy=True):
|
||||||
bdm_ref = models.BlockDeviceMapping()
|
bdm_ref = models.BlockDeviceMapping()
|
||||||
bdm_ref.update(values)
|
bdm_ref.update(values)
|
||||||
bdm_ref.save()
|
bdm_ref.save()
|
||||||
|
return bdm_ref
|
||||||
|
|
||||||
|
|
||||||
@require_context
|
@require_context
|
||||||
def block_device_mapping_update(context, bdm_id, values, legacy=True):
|
def block_device_mapping_update(context, bdm_id, values, legacy=True):
|
||||||
_scrub_empty_str_values(values, ['volume_size'])
|
_scrub_empty_str_values(values, ['volume_size'])
|
||||||
values = _from_legacy_values(values, legacy, allow_updates=True)
|
values = _from_legacy_values(values, legacy, allow_updates=True)
|
||||||
_block_device_mapping_get_query(context).\
|
query = _block_device_mapping_get_query(context).filter_by(id=bdm_id)
|
||||||
filter_by(id=bdm_id).\
|
query.update(values)
|
||||||
update(values)
|
return query.first()
|
||||||
|
|
||||||
|
|
||||||
def block_device_mapping_update_or_create(context, values, legacy=True):
|
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 = models.BlockDeviceMapping()
|
||||||
bdm_ref.update(values)
|
bdm_ref.update(values)
|
||||||
bdm_ref.save(session=session)
|
bdm_ref.save(session=session)
|
||||||
|
result = bdm_ref
|
||||||
else:
|
else:
|
||||||
values = _from_legacy_values(values, legacy, allow_updates=True)
|
values = _from_legacy_values(values, legacy, allow_updates=True)
|
||||||
result.update(values)
|
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 == None,
|
||||||
models.BlockDeviceMapping.guest_format != 'swap')).
|
models.BlockDeviceMapping.guest_format != 'swap')).
|
||||||
soft_delete())
|
soft_delete())
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
@require_context
|
@require_context
|
||||||
|
|
|
@ -2121,6 +2121,7 @@ class CloudTestCase(test.TestCase):
|
||||||
return [dict(id=1,
|
return [dict(id=1,
|
||||||
source_type='snapshot',
|
source_type='snapshot',
|
||||||
destination_type='volume',
|
destination_type='volume',
|
||||||
|
instance_uuid=inst_id,
|
||||||
snapshot_id=snapshots[0],
|
snapshot_id=snapshots[0],
|
||||||
volume_id=volumes[0],
|
volume_id=volumes[0],
|
||||||
volume_size=1,
|
volume_size=1,
|
||||||
|
|
|
@ -548,3 +548,27 @@ class CellsManagerClassTestCase(test.TestCase):
|
||||||
instance_uuid=instance_uuid, console_port=console_port,
|
instance_uuid=instance_uuid, console_port=console_port,
|
||||||
console_type=console_type)
|
console_type=console_type)
|
||||||
self.assertEqual('fake-response', response)
|
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')
|
||||||
|
|
|
@ -1425,3 +1425,173 @@ class CellsBroadcastMethodsTestCase(test.TestCase):
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
self.src_msg_runner.consoleauth_delete_tokens(self.ctxt, fake_uuid)
|
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)
|
||||||
|
|
|
@ -422,3 +422,29 @@ class CellsAPITestCase(test.TestCase):
|
||||||
self._check_result(call_info, 'validate_console_port',
|
self._check_result(call_info, 'validate_console_port',
|
||||||
expected_args, version='1.6')
|
expected_args, version='1.6')
|
||||||
self.assertEqual(result, 'fake_response')
|
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')
|
||||||
|
|
|
@ -632,13 +632,28 @@ class ConductorTestCase(_BaseTestCase, test.TestCase):
|
||||||
self.conductor_manager = self.conductor
|
self.conductor_manager = self.conductor
|
||||||
|
|
||||||
def test_block_device_mapping_update_or_create(self):
|
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_create')
|
||||||
self.mox.StubOutWithMock(db, 'block_device_mapping_update')
|
self.mox.StubOutWithMock(db, 'block_device_mapping_update')
|
||||||
self.mox.StubOutWithMock(db, 'block_device_mapping_update_or_create')
|
self.mox.StubOutWithMock(db, 'block_device_mapping_update_or_create')
|
||||||
db.block_device_mapping_create(self.context, fake_bdm)
|
self.mox.StubOutWithMock(cells_rpcapi,
|
||||||
db.block_device_mapping_update(self.context, fake_bdm['id'], fake_bdm)
|
'bdm_update_or_create_at_top')
|
||||||
db.block_device_mapping_update_or_create(self.context, fake_bdm)
|
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.mox.ReplayAll()
|
||||||
self.conductor.block_device_mapping_update_or_create(self.context,
|
self.conductor.block_device_mapping_update_or_create(self.context,
|
||||||
fake_bdm,
|
fake_bdm,
|
||||||
|
@ -650,22 +665,44 @@ class ConductorTestCase(_BaseTestCase, test.TestCase):
|
||||||
fake_bdm)
|
fake_bdm)
|
||||||
|
|
||||||
def test_block_device_mapping_destroy(self):
|
def test_block_device_mapping_destroy(self):
|
||||||
fake_bdm = {'id': 'fake-bdm'}
|
fake_bdm = {'id': 'fake-bdm',
|
||||||
fake_bdm2 = {'id': 'fake-bdm-2'}
|
'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'}
|
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')
|
||||||
self.mox.StubOutWithMock(
|
self.mox.StubOutWithMock(
|
||||||
db, 'block_device_mapping_destroy_by_instance_and_device')
|
db, 'block_device_mapping_destroy_by_instance_and_device')
|
||||||
self.mox.StubOutWithMock(
|
self.mox.StubOutWithMock(
|
||||||
db, 'block_device_mapping_destroy_by_instance_and_volume')
|
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')
|
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')
|
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,
|
db.block_device_mapping_destroy_by_instance_and_device(self.context,
|
||||||
'fake-uuid',
|
'fake-uuid',
|
||||||
'fake-device')
|
'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,
|
db.block_device_mapping_destroy_by_instance_and_volume(self.context,
|
||||||
'fake-uuid',
|
'fake-uuid',
|
||||||
'fake-volume')
|
'fake-volume')
|
||||||
|
cells_rpcapi.bdm_destroy_at_top(self.context, fake_inst['uuid'],
|
||||||
|
volume_id='fake-volume')
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
self.conductor.block_device_mapping_destroy(self.context,
|
self.conductor.block_device_mapping_destroy(self.context,
|
||||||
[fake_bdm,
|
[fake_bdm,
|
||||||
|
@ -810,8 +847,12 @@ class ConductorRPCAPITestCase(_BaseTestCase, test.TestCase):
|
||||||
fake_bdm)
|
fake_bdm)
|
||||||
|
|
||||||
def test_block_device_mapping_destroy(self):
|
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'}
|
fake_inst = {'uuid': 'fake-uuid'}
|
||||||
|
|
||||||
self.mox.StubOutWithMock(db, 'block_device_mapping_destroy')
|
self.mox.StubOutWithMock(db, 'block_device_mapping_destroy')
|
||||||
self.mox.StubOutWithMock(
|
self.mox.StubOutWithMock(
|
||||||
db, 'block_device_mapping_destroy_by_instance_and_device')
|
db, 'block_device_mapping_destroy_by_instance_and_device')
|
||||||
|
@ -961,8 +1002,12 @@ class ConductorAPITestCase(_BaseTestCase, test.TestCase):
|
||||||
'fake-bdm')
|
'fake-bdm')
|
||||||
|
|
||||||
def test_block_device_mapping_destroy(self):
|
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'}
|
fake_inst = {'uuid': 'fake-uuid'}
|
||||||
|
|
||||||
self.mox.StubOutWithMock(db, 'block_device_mapping_destroy')
|
self.mox.StubOutWithMock(db, 'block_device_mapping_destroy')
|
||||||
self.mox.StubOutWithMock(
|
self.mox.StubOutWithMock(
|
||||||
db, 'block_device_mapping_destroy_by_instance_and_device')
|
db, 'block_device_mapping_destroy_by_instance_and_device')
|
||||||
|
|
|
@ -4039,12 +4039,15 @@ class BlockDeviceMappingTestCase(test.TestCase):
|
||||||
|
|
||||||
def test_block_device_mapping_update(self):
|
def test_block_device_mapping_update(self):
|
||||||
bdm = self._create_bdm({})
|
bdm = self._create_bdm({})
|
||||||
db.block_device_mapping_update(self.ctxt, bdm['id'],
|
result = db.block_device_mapping_update(
|
||||||
{'destination_type': 'moon'},
|
self.ctxt, bdm['id'], {'destination_type': 'moon'},
|
||||||
legacy=False)
|
legacy=False)
|
||||||
uuid = bdm['instance_uuid']
|
uuid = bdm['instance_uuid']
|
||||||
bdm_real = db.block_device_mapping_get_all_by_instance(self.ctxt, uuid)
|
bdm_real = db.block_device_mapping_get_all_by_instance(self.ctxt, uuid)
|
||||||
self.assertEqual(bdm_real[0]['destination_type'], 'moon')
|
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):
|
def test_block_device_mapping_update_or_create(self):
|
||||||
values = {
|
values = {
|
||||||
|
|
Loading…
Reference in New Issue