Track which cell each instance is created in and use it consistently

In conductor's instance create path we were using the last cell of the
create loop for the second loop that created extra resources like BDMs,
after the quota recheck.

Co-Authored-By: Matt Riedemann <mriedem.os@gmail.com>

Change-Id: Iea8db52e7026166fb6623e0cc1aebdcc0af1d691
Closes-Bug: #1715493
This commit is contained in:
Dan Smith 2017-09-06 14:19:05 -07:00 committed by Matt Riedemann
parent bcd1f1d8c8
commit e801775959
2 changed files with 54 additions and 0 deletions

View File

@ -942,6 +942,7 @@ class ComputeTaskManager(base.Base):
return
host_mapping_cache = {}
cell_mapping_cache = {}
instances = []
for (build_request, request_spec, host) in six.moves.zip(
@ -988,6 +989,7 @@ class ComputeTaskManager(base.Base):
with obj_target_cell(instance, cell):
instance.create()
instances.append(instance)
cell_mapping_cache[instance.uuid] = cell
# NOTE(melwitt): We recheck the quota after creating the
# objects to prevent users from allocating more resources
@ -1011,6 +1013,7 @@ class ComputeTaskManager(base.Base):
# Skip placeholders that were buried in cell0 or had their
# build requests deleted by the user before instance create.
continue
cell = cell_mapping_cache[instance.uuid]
filter_props = request_spec.to_legacy_filter_properties_dict()
scheduler_utils.populate_retry(filter_props, instance.uuid)
scheduler_utils.populate_filter_properties(filter_props,

View File

@ -1550,6 +1550,57 @@ class ConductorTaskTestCase(_BaseTaskTestCase, test_compute.BaseTestCase):
self.conductor.schedule_and_build_instances(**params)
self.assertEqual(3, build_and_run_instance.call_count)
@mock.patch('nova.compute.rpcapi.ComputeAPI.build_and_run_instance')
@mock.patch('nova.scheduler.rpcapi.SchedulerAPI.select_destinations')
@mock.patch('nova.objects.HostMapping.get_by_host')
def test_schedule_and_build_multiple_cells(
self, get_hostmapping, select_destinations,
build_and_run_instance):
"""Test that creates two instances in separate cells."""
# This list needs to match the number of build_requests and the number
# of request_specs in params.
select_destinations.return_value = [{'host': 'fake-host',
'nodename': 'fake-nodename',
'limits': None},
{'host': 'fake-host2',
'nodename': 'fake-nodename2',
'limits': None}]
params = self.params
# The cells are created in the base TestCase setup.
self.start_service('compute', host='fake-host', cell='cell1')
self.start_service('compute', host='fake-host2', cell='cell2')
get_hostmapping.side_effect = self.host_mappings.values()
# create an additional build request and request spec
build_request = fake_build_request.fake_req_obj(self.ctxt)
del build_request.instance.id
build_request.create()
params['build_requests'].objects.append(build_request)
im2 = objects.InstanceMapping(
self.ctxt, instance_uuid=build_request.instance.uuid,
cell_mapping=None, project_id=self.ctxt.project_id)
im2.create()
params['request_specs'].append(objects.RequestSpec(
instance_uuid=build_request.instance_uuid,
instance_group=None))
instance_cells = set()
def _build_and_run_instance(ctxt, *args, **kwargs):
instance = kwargs['instance']
# Keep track of the cells that the instances were created in.
inst_mapping = objects.InstanceMapping.get_by_instance_uuid(
ctxt, instance.uuid)
instance_cells.add(inst_mapping.cell_mapping.uuid)
build_and_run_instance.side_effect = _build_and_run_instance
self.conductor.schedule_and_build_instances(**params)
self.assertEqual(2, build_and_run_instance.call_count)
self.assertEqual(2, len(instance_cells))
@mock.patch('nova.scheduler.rpcapi.SchedulerAPI.select_destinations')
def test_schedule_and_build_scheduler_failure(self, select_destinations):
select_destinations.side_effect = Exception