Ensure we unshelve in the cell the instance is mapped

When we create a server it gets put in a specific cell and its
instance_mappings record in the API DB is set to map that instance
to that cell.

When unshelving an instance we want to ensure that the scheduler
only considers compute nodes in the cell where the instance is
mapped.

Change-Id: I96285a1902436cf59b6c6ddf22b69a33503d0f4a
Closes-Bug: #1702935
This commit is contained in:
Chris Friesen 2017-07-21 13:25:48 -06:00 committed by Matt Riedemann
parent f590636b59
commit 06b4ff7df8
2 changed files with 59 additions and 7 deletions

View File

@ -686,6 +686,23 @@ class ComputeTaskManager(base.Base):
instance.uuid)
request_spec = objects.RequestSpec.from_primitives(
context, request_spec, filter_properties)
# NOTE(cfriesen): Ensure that we restrict the scheduler to
# the cell specified by the instance mapping.
instance_mapping = \
objects.InstanceMapping.get_by_instance_uuid(
context, instance.uuid)
LOG.debug('Requesting cell %(cell)s while unshelving',
{'cell': instance_mapping.cell_mapping.identity},
instance=instance)
if ('requested_destination' in request_spec and
request_spec.requested_destination):
request_spec.requested_destination.cell = (
instance_mapping.cell_mapping)
else:
request_spec.requested_destination = (
objects.Destination(
cell=instance_mapping.cell_mapping))
hosts = self._schedule_instances(context, request_spec,
[instance.uuid])
host_state = hosts[0]

View File

@ -928,6 +928,7 @@ class _BaseTaskTestCase(object):
# unshelve_instance() is a cast, we need to wait for it to complete
self.useFixture(cast_as_call.CastAsCall(self.stubs))
@mock.patch.object(objects.InstanceMapping, 'get_by_instance_uuid')
@mock.patch.object(self.conductor_manager.compute_rpcapi,
'unshelve_instance')
@mock.patch.object(scheduler_utils, 'populate_filter_properties')
@ -941,7 +942,11 @@ class _BaseTaskTestCase(object):
def do_test(reset_forced_destinations,
to_filtprops, to_reqspec, from_primitives, sched_instances,
populate_retry, populate_filter_properties,
unshelve_instance):
unshelve_instance, get_by_instance_uuid):
cell_mapping = objects.CellMapping.get_by_uuid(self.context,
uuids.cell1)
get_by_instance_uuid.return_value = objects.InstanceMapping(
cell_mapping=cell_mapping)
to_filtprops.return_value = filter_properties
to_reqspec.return_value = request_spec
from_primitives.return_value = fake_spec
@ -952,6 +957,8 @@ class _BaseTaskTestCase(object):
filter_properties)
sched_instances.assert_called_once_with(self.context, fake_spec,
[instance.uuid])
self.assertEqual(cell_mapping,
fake_spec.requested_destination.cell)
# NOTE(sbauza): Since the instance is dehydrated when passing
# through the RPC API, we can only assert mock.ANY for it
unshelve_instance.assert_called_once_with(
@ -1000,17 +1007,31 @@ class _BaseTaskTestCase(object):
'_schedule_instances'),
mock.patch.object(self.conductor_manager.compute_rpcapi,
'unshelve_instance'),
) as (schedule_mock, unshelve_mock):
mock.patch.object(objects.InstanceMapping,
'get_by_instance_uuid'),
) as (schedule_mock, unshelve_mock, get_by_instance_uuid):
schedule_mock.return_value = [{'host': 'fake_host',
'nodename': 'fake_node',
'limits': {}}]
get_by_instance_uuid.return_value = objects.InstanceMapping(
cell_mapping=objects.CellMapping.get_by_uuid(
self.context, uuids.cell1))
self.conductor_manager.unshelve_instance(self.context, instance)
self.assertEqual(1, unshelve_mock.call_count)
@mock.patch.object(objects.InstanceMapping, 'get_by_instance_uuid')
@mock.patch.object(objects.RequestSpec, 'from_primitives')
def test_unshelve_instance_schedule_and_rebuild(self, fp):
def test_unshelve_instance_schedule_and_rebuild(self, fp, mock_im):
fake_spec = objects.RequestSpec()
# Set requested_destination to test setting cell_mapping in
# existing object.
fake_spec.requested_destination = objects.Destination(
host="dummy", cell=None)
fp.return_value = fake_spec
cell_mapping = objects.CellMapping.get_by_uuid(self.context,
uuids.cell1)
mock_im.return_value = objects.InstanceMapping(
cell_mapping=cell_mapping)
instance = self._create_fake_instance_obj()
instance.vm_state = vm_states.SHELVED_OFFLOADED
instance.save()
@ -1045,6 +1066,7 @@ class _BaseTaskTestCase(object):
system_metadata['shelved_host'] = 'fake-mini'
self.conductor_manager.unshelve_instance(self.context, instance)
fp.assert_called_once_with(self.context, 'req_spec', mock.ANY)
self.assertEqual(cell_mapping, fake_spec.requested_destination.cell)
def test_unshelve_instance_schedule_and_rebuild_novalid_host(self):
instance = self._create_fake_instance_obj()
@ -1059,8 +1081,12 @@ class _BaseTaskTestCase(object):
mock.patch.object(self.conductor_manager.image_api, 'get',
return_value='fake_image'),
mock.patch.object(self.conductor_manager, '_schedule_instances',
fake_schedule_instances)
) as (_get_image, _schedule_instances):
fake_schedule_instances),
mock.patch.object(objects.InstanceMapping, 'get_by_instance_uuid')
) as (_get_image, _schedule_instances, get_by_instance_uuid):
get_by_instance_uuid.return_value = objects.InstanceMapping(
cell_mapping=objects.CellMapping.get_by_uuid(
self.context, uuids.cell1))
system_metadata['shelved_at'] = timeutils.utcnow()
system_metadata['shelved_image_id'] = 'fake_image_id'
system_metadata['shelved_host'] = 'fake-mini'
@ -1070,12 +1096,16 @@ class _BaseTaskTestCase(object):
show_deleted=False)])
self.assertEqual(vm_states.SHELVED_OFFLOADED, instance.vm_state)
@mock.patch.object(objects.InstanceMapping, 'get_by_instance_uuid')
@mock.patch.object(conductor_manager.ComputeTaskManager,
'_schedule_instances',
side_effect=messaging.MessagingTimeout())
@mock.patch.object(image_api.API, 'get', return_value='fake_image')
def test_unshelve_instance_schedule_and_rebuild_messaging_exception(
self, mock_get_image, mock_schedule_instances):
self, mock_get_image, mock_schedule_instances, mock_im):
mock_im.return_value = objects.InstanceMapping(
cell_mapping=objects.CellMapping.get_by_uuid(self.context,
uuids.cell1))
instance = self._create_fake_instance_obj()
instance.vm_state = vm_states.SHELVED_OFFLOADED
instance.task_state = task_states.UNSHELVING
@ -1094,10 +1124,15 @@ class _BaseTaskTestCase(object):
self.assertEqual(vm_states.SHELVED_OFFLOADED, instance.vm_state)
self.assertIsNone(instance.task_state)
@mock.patch.object(objects.InstanceMapping, 'get_by_instance_uuid')
@mock.patch.object(objects.RequestSpec, 'from_primitives')
def test_unshelve_instance_schedule_and_rebuild_volume_backed(self, fp):
def test_unshelve_instance_schedule_and_rebuild_volume_backed(
self, fp, mock_im):
fake_spec = objects.RequestSpec()
fp.return_value = fake_spec
mock_im.return_value = objects.InstanceMapping(
cell_mapping=objects.CellMapping.get_by_uuid(self.context,
uuids.cell1))
instance = self._create_fake_instance_obj()
instance.vm_state = vm_states.SHELVED_OFFLOADED
instance.save()