Retrieve the allocations early

Moves the allocation retrieving early, it will be passed to
instance_claim/rebuild_claim/resize_claim in ResourceTracker,
then we can claim resources according to allocations.

Change-Id: I59aec72e158eb2859bb6178b2a42d3f3438ab0f3
Partially-Implements: blueprint virtual-persistent-memory
Co-Authored-By: He Jie Xu <hejie.xu@intel.com>
This commit is contained in:
LuyaoZhong 2019-09-11 10:14:44 +00:00
parent f45368e02f
commit faf7f33980
7 changed files with 97 additions and 100 deletions

View File

@ -2213,10 +2213,15 @@ class ComputeManager(manager.Manager):
self._update_pci_request_spec_with_allocated_interface_name(
context, instance, request_group_resource_providers_mapping)
# TODO(Luyao) cut over to get_allocs_for_consumer
allocs = self.reportclient.get_allocations_for_consumer(
context, instance.uuid)
try:
scheduler_hints = self._get_scheduler_hints(filter_properties,
request_spec)
with self.rt.instance_claim(context, instance, node, limits):
with self.rt.instance_claim(context, instance, node, allocs,
limits):
# NOTE(russellb) It's important that this validation be done
# *after* the resource tracker instance claim, as that is where
# the host is set on the instance.
@ -2240,7 +2245,6 @@ class ComputeManager(manager.Manager):
task_states.BLOCK_DEVICE_MAPPING)
block_device_info = resources['block_device_info']
network_info = resources['network_info']
allocs = resources['allocations']
LOG.debug('Start spawning the instance on the hypervisor.',
instance=instance)
with timeutils.StopWatch() as timer:
@ -2470,21 +2474,6 @@ class ComputeManager(manager.Manager):
raise exception.BuildAbortException(instance_uuid=instance.uuid,
reason=msg)
try:
resources['allocations'] = (
self.reportclient.get_allocations_for_consumer(context,
instance.uuid))
except Exception:
LOG.exception('Failure retrieving placement allocations',
instance=instance)
# Make sure the async call finishes
if network_info is not None:
network_info.wait(do_raise=False)
self.driver.failed_spawn_cleanup(instance)
msg = _('Failure retrieving placement allocations')
raise exception.BuildAbortException(instance_uuid=instance.uuid,
reason=msg)
try:
yield resources
except Exception as exc:
@ -3154,17 +3143,20 @@ class ComputeManager(manager.Manager):
else:
scheduled_node = instance.node
allocs = self.reportclient.get_allocations_for_consumer(
context, instance.uuid)
with self._error_out_instance_on_exception(context, instance):
try:
claim_ctxt = rebuild_claim(
context, instance, scheduled_node,
context, instance, scheduled_node, allocs,
limits=limits, image_meta=image_meta,
migration=migration)
self._do_rebuild_instance_with_claim(
claim_ctxt, context, instance, orig_image_ref,
image_meta, injected_files, new_pass, orig_sys_metadata,
bdms, evacuate, on_shared_storage, preserve_ephemeral,
migration, request_spec)
migration, request_spec, allocs)
except (exception.ComputeResourcesUnavailable,
exception.RescheduledException) as e:
if isinstance(e, exception.ComputeResourcesUnavailable):
@ -3239,7 +3231,7 @@ class ComputeManager(manager.Manager):
image_meta, injected_files, new_pass,
orig_sys_metadata, bdms, evacuate,
on_shared_storage, preserve_ephemeral,
migration, request_spec):
migration, request_spec, allocations):
orig_vm_state = instance.vm_state
if evacuate:
@ -3335,9 +3327,6 @@ class ComputeManager(manager.Manager):
else:
network_info = instance.get_network_info()
allocations = self.reportclient.get_allocations_for_consumer(
context, instance.uuid)
if bdms is None:
bdms = objects.BlockDeviceMappingList.get_by_instance_uuid(
context, instance.uuid)
@ -4429,8 +4418,10 @@ class ComputeManager(manager.Manager):
instance.save()
limits = filter_properties.get('limits', {})
allocs = self.reportclient.get_allocations_for_consumer(
context, instance.uuid)
with self.rt.resize_claim(context, instance, instance_type, node,
migration, image_meta=image,
migration, allocs, image_meta=image,
limits=limits) as claim:
LOG.info('Migrating', instance=instance)
# RPC cast to the source host to start the actual resize/migration.
@ -5443,7 +5434,8 @@ class ComputeManager(manager.Manager):
self.host)
network_info = self.network_api.get_instance_nw_info(context, instance)
try:
with self.rt.instance_claim(context, instance, node, limits):
with self.rt.instance_claim(context, instance, node, allocations,
limits):
self.driver.spawn(context, instance, image_meta,
injected_files=[],
admin_password=None,

View File

@ -153,7 +153,8 @@ class ResourceTracker(object):
self.disk_allocation_ratio = CONF.disk_allocation_ratio
@utils.synchronized(COMPUTE_RESOURCE_SEMAPHORE)
def instance_claim(self, context, instance, nodename, limits=None):
def instance_claim(self, context, instance, nodename, allocations,
limits=None):
"""Indicate that some resources are needed for an upcoming compute
instance build operation.
@ -164,6 +165,7 @@ class ResourceTracker(object):
:param instance: instance to reserve resources for.
:type instance: nova.objects.instance.Instance object
:param nodename: The Ironic nodename selected by the scheduler
:param allocations: The placement allocation records for the instance.
:param limits: Dict of oversubscription limits for memory, disk,
and CPUs.
:returns: A Claim ticket representing the reserved resources. It can
@ -223,24 +225,24 @@ class ResourceTracker(object):
return claim
@utils.synchronized(COMPUTE_RESOURCE_SEMAPHORE)
def rebuild_claim(self, context, instance, nodename, limits=None,
image_meta=None, migration=None):
def rebuild_claim(self, context, instance, nodename, allocations,
limits=None, image_meta=None, migration=None):
"""Create a claim for a rebuild operation."""
instance_type = instance.flavor
return self._move_claim(context, instance, instance_type, nodename,
migration, move_type='evacuation',
migration, allocations, move_type='evacuation',
limits=limits, image_meta=image_meta)
@utils.synchronized(COMPUTE_RESOURCE_SEMAPHORE)
def resize_claim(self, context, instance, instance_type, nodename,
migration, image_meta=None, limits=None):
migration, allocations, image_meta=None, limits=None):
"""Create a claim for a resize or cold-migration move.
Note that this code assumes ``instance.new_flavor`` is set when
resizing with a new flavor.
"""
return self._move_claim(context, instance, instance_type, nodename,
migration, image_meta=image_meta,
migration, allocations, image_meta=image_meta,
limits=limits)
@utils.synchronized(COMPUTE_RESOURCE_SEMAPHORE)
@ -260,12 +262,15 @@ class ResourceTracker(object):
# Flavor and image cannot change during a live migration.
instance_type = instance.flavor
image_meta = instance.image_meta
# TODO(Luyao) will pass allocations to live_migration_claim after the
# live migration change is done, now just set it None to _move_claim
return self._move_claim(context, instance, instance_type, nodename,
migration, move_type='live-migration',
migration, None, move_type='live-migration',
image_meta=image_meta, limits=limits)
def _move_claim(self, context, instance, new_instance_type, nodename,
migration, move_type=None, image_meta=None, limits=None):
migration, allocations, move_type=None,
image_meta=None, limits=None):
"""Indicate that resources are needed for a move to this host.
Move can be either a migrate/resize, live-migrate or an
@ -275,13 +280,14 @@ class ResourceTracker(object):
:param instance: instance object to reserve resources for
:param new_instance_type: new instance_type being resized to
:param nodename: The Ironic nodename selected by the scheduler
:param image_meta: instance image metadata
:param move_type: move type - can be one of 'migration', 'resize',
'live-migration', 'evacuate'
:param limits: Dict of oversubscription limits for memory, disk,
and CPUs
:param migration: A migration object if one was already created
elsewhere for this operation (otherwise None)
:param allocations: the placement allocation records.
:param move_type: move type - can be one of 'migration', 'resize',
'live-migration', 'evacuate'
:param image_meta: instance image metadata
:param limits: Dict of oversubscription limits for memory, disk,
and CPUs
:returns: A Claim ticket representing the reserved resources. This
should be turned into finalize a resource claim or free
resources after the compute operation is finished.

View File

@ -262,7 +262,7 @@ class IronicResourceTrackerTest(test_base.SchedulerReportClientTestBase):
cn1_obj = self.COMPUTE_NODE_FIXTURES[uuids.cn1]
cn1_nodename = cn1_obj.hypervisor_hostname
inst = self.instances[uuids.instance1]
with self.rt.instance_claim(self.ctx, inst, cn1_nodename):
with self.rt.instance_claim(self.ctx, inst, cn1_nodename, {}):
_assert_stats()

View File

@ -7925,7 +7925,7 @@ class ComputeTestCase(BaseTestCase,
instance = self._create_fake_instance_obj()
instance.vcpus = 1
self.compute.rt.instance_claim(admin_context, instance, NODENAME)
self.compute.rt.instance_claim(admin_context, instance, NODENAME, None)
self.assertEqual(1, cn.vcpus_used)
self.compute.terminate_instance(admin_context, instance, [])
@ -7948,7 +7948,7 @@ class ComputeTestCase(BaseTestCase,
self.assertEqual(0, cn.vcpus_used)
self.compute.rt.instance_claim(admin_context, instance, NODENAME)
self.compute.rt.instance_claim(admin_context, instance, NODENAME, None)
self.compute._init_instance(admin_context, instance)
self.assertEqual(1, cn.vcpus_used)
@ -12806,6 +12806,7 @@ class EvacuateHostTestCase(BaseTestCase):
ctxt, self.inst, self.inst.host)
mock_setup_instance_network_on_host.assert_called_once_with(
ctxt, self.inst, self.inst.host, migration)
self.mock_get_allocs.assert_called_once_with(ctxt, self.inst.uuid)
_test_rebuild(vm_is_stopped=vm_states_is_stopped)

View File

@ -93,6 +93,15 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase,
self.useFixture(fixtures.SpawnIsSynchronousFixture())
self.useFixture(fixtures.EventReporterStub())
self.allocations = {
uuids.provider1: {
"generation": 0,
"resources": {
"VCPU": 1,
"MEMORY_MB": 512
}
}
}
@mock.patch.object(manager.ComputeManager, '_get_power_state')
@mock.patch.object(manager.ComputeManager, '_sync_instance_power_state')
@ -4702,7 +4711,8 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase,
injected_files, new_pass,
orig_sys_metadata, bdms,
recreate, on_shared_storage,
preserve_ephemeral, {}, {})
preserve_ephemeral, {}, {},
self.allocations)
mock_notify_usage.assert_has_calls(
[mock.call(self.context, instance, "rebuild.start",
@ -4798,7 +4808,8 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase,
orig_sys_metadata={}, bdms=objects.BlockDeviceMapping(),
evacuate=False, on_shared_storage=None,
preserve_ephemeral=False, migration=objects.Migration(),
request_spec=objects.RequestSpec())
request_spec=objects.RequestSpec(),
allocations=self.allocations)
self.assertIn('Trusted image certificates provided on host',
six.text_type(ex))
@ -5385,15 +5396,15 @@ class ComputeManagerBuildInstanceTestCase(test.NoDBTestCase):
self.compute.driver)
self.compute.rt = fake_rt
self.allocations = [{
"resource_provider": {
"uuid": uuids.rp1,
},
"resources": {
"VCPU": 1,
"MEMORY_MB": 512,
},
}]
self.allocations = {
uuids.provider1: {
"generation": 0,
"resources": {
"VCPU": 1,
"MEMORY_MB": 512
}
}
}
self.mock_get_allocs = self.useFixture(
fixtures.fixtures.MockPatchObject(
self.compute.reportclient,
@ -6319,7 +6330,7 @@ class ComputeManagerBuildInstanceTestCase(test.NoDBTestCase):
self._instance_action_events(mock_start, mock_finish)
self._assert_build_instance_update(mock_save, reschedule_update=True)
mock_claim.assert_called_once_with(self.context, self.instance,
self.node, self.limits)
self.node, self.allocations, self.limits)
mock_notify.assert_has_calls([
mock.call(self.context, self.instance, 'create.start',
extra_usage_info= {'image_name': self.image.get('name')}),
@ -6571,33 +6582,6 @@ class ComputeManagerBuildInstanceTestCase(test.NoDBTestCase):
mock_prepspawn.assert_not_called()
mock_failedspawn.assert_not_called()
@mock.patch.object(virt_driver.ComputeDriver, 'failed_spawn_cleanup')
@mock.patch.object(virt_driver.ComputeDriver, 'prepare_for_spawn')
@mock.patch('nova.network.model.NetworkInfoAsyncWrapper.wait')
@mock.patch.object(manager.ComputeManager, '_build_networks_for_instance')
@mock.patch('nova.objects.Instance.save')
def test_build_resources_aborts_on_failed_allocations_get(
self, mock_save, mock_bn, mock_net_wait, mock_prepspawn,
mock_failedspawn):
mock_bn.return_value = self.network_info
mock_save.return_value = self.instance
self.mock_get_allocs.side_effect = exception.NotFound()
try:
with self.compute._build_resources(
self.context, self.instance, self.requested_networks,
self.security_groups, self.image,
self.block_device_mapping, self.resource_provider_mapping):
pass
except Exception as e:
self.assertIsInstance(e, exception.BuildAbortException)
self.mock_get_allocs.assert_called_once_with(self.context,
self.instance.uuid)
mock_net_wait.assert_called_once_with(do_raise=False)
mock_prepspawn.assert_called_once_with(self.instance)
mock_failedspawn.assert_called_once_with(self.instance)
@mock.patch.object(virt_driver.ComputeDriver, 'failed_spawn_cleanup')
@mock.patch.object(virt_driver.ComputeDriver, 'prepare_for_spawn')
@mock.patch.object(manager.ComputeManager, '_build_networks_for_instance')

View File

@ -474,6 +474,15 @@ class BaseTestCase(test.NoDBTestCase):
reserved_host_disk_mb=0,
reserved_host_memory_mb=0,
reserved_host_cpus=0)
self.allocations = {
_COMPUTE_NODE_FIXTURES[0].uuid: {
"generation": 0,
"resources": {
"VCPU": 1,
"MEMORY_MB": 512
}
}
}
def _setup_rt(self, virt_resources=_VIRT_DRIVER_AVAIL_RESOURCES):
(self.rt, self.sched_client_mock, self.report_client_mock,
@ -1906,7 +1915,7 @@ class TestInstanceClaim(BaseTestCase):
with mock.patch.object(self.instance, 'save'):
claim = self.rt.instance_claim(mock.sentinel.ctx, self.instance,
_NODENAME, None)
_NODENAME, self.allocations, None)
self.assertEqual(self.rt.host, self.instance.host)
self.assertEqual(self.rt.host, self.instance.launched_on)
@ -1950,7 +1959,7 @@ class TestInstanceClaim(BaseTestCase):
with mock.patch.object(self.rt, '_update') as update_mock:
with mock.patch.object(self.instance, 'save'):
self.rt.instance_claim(self.ctx, self.instance, _NODENAME,
None)
self.allocations, None)
cn = self.rt.compute_nodes[_NODENAME]
update_mock.assert_called_once_with(self.elevated, cn)
self.assertTrue(obj_base.obj_equal_prims(expected, cn))
@ -1987,7 +1996,7 @@ class TestInstanceClaim(BaseTestCase):
with mock.patch.object(self.rt, '_update') as update_mock:
with mock.patch.object(self.instance, 'save'):
self.rt.instance_claim(self.ctx, self.instance, _NODENAME,
None)
self.allocations, None)
cn = self.rt.compute_nodes[_NODENAME]
update_mock.assert_called_once_with(self.elevated, cn)
self.assertTrue(obj_base.obj_equal_prims(expected, cn))
@ -2042,7 +2051,7 @@ class TestInstanceClaim(BaseTestCase):
with mock.patch.object(self.rt, '_update') as update_mock:
with mock.patch.object(self.instance, 'save'):
self.rt.instance_claim(self.ctx, self.instance, _NODENAME,
None)
self.allocations, None)
cn = self.rt.compute_nodes[_NODENAME]
update_mock.assert_called_once_with(self.elevated, cn)
self.assertTrue(obj_base.obj_equal_prims(expected, cn))
@ -2102,7 +2111,7 @@ class TestInstanceClaim(BaseTestCase):
with mock.patch.object(self.rt, '_update') as update_mock:
with mock.patch.object(self.instance, 'save'):
self.rt.instance_claim(self.ctx, self.instance, _NODENAME,
None)
self.allocations, None)
cn = self.rt.compute_nodes[_NODENAME]
update_mock.assert_called_once_with(self.elevated, cn)
pci_stats_mock.assert_called_once_with([request])
@ -2132,7 +2141,7 @@ class TestInstanceClaim(BaseTestCase):
return_value=self.instance)
def _doit(mock_clone):
with self.rt.instance_claim(self.ctx, self.instance, _NODENAME,
None):
self.allocations, None):
# Raise an exception. Just make sure below that the abort()
# method of the claim object was called (and the resulting
# resources reset to the pre-claimed amounts)
@ -2165,7 +2174,7 @@ class TestInstanceClaim(BaseTestCase):
@mock.patch.object(self.instance, 'save')
def _claim(mock_save, mock_clone):
return self.rt.instance_claim(self.ctx, self.instance, _NODENAME,
None)
self.allocations, None)
cn = self.rt.compute_nodes[_NODENAME]
@ -2215,7 +2224,7 @@ class TestInstanceClaim(BaseTestCase):
with mock.patch.object(self.rt, '_update') as update_mock:
with mock.patch.object(self.instance, 'save'):
self.rt.instance_claim(self.ctx, self.instance, _NODENAME,
limits)
self.allocations, limits)
update_mock.assert_called_once_with(self.ctx.elevated(), cn)
new_numa = cn.numa_topology
new_numa = objects.NUMATopology.obj_from_db_obj(new_numa)
@ -2304,7 +2313,7 @@ class TestResize(BaseTestCase):
mock.patch('nova.objects.Instance.save'),
) as (create_mig_mock, ctxt_mock, inst_save_mock):
claim = self.rt.resize_claim(ctx, instance, new_flavor, _NODENAME,
None)
None, self.allocations)
create_mig_mock.assert_called_once_with(
ctx, instance, new_flavor, _NODENAME,
@ -2374,7 +2383,8 @@ class TestResize(BaseTestCase):
# Build instance
with mock.patch.object(instance, 'save'):
self.rt.instance_claim(ctx, instance, _NODENAME, None)
self.rt.instance_claim(ctx, instance, _NODENAME,
self.allocations, None)
expected = compute_update_usage(expected, old_flavor, sign=1)
expected.running_vms = 1
@ -2413,7 +2423,8 @@ class TestResize(BaseTestCase):
return_value=mig_context_obj),
mock.patch('nova.objects.Instance.save'),
) as (create_mig_mock, ctxt_mock, inst_save_mock):
self.rt.resize_claim(ctx, instance, new_flavor, _NODENAME, None)
self.rt.resize_claim(ctx, instance, new_flavor, _NODENAME,
None, self.allocations)
expected = compute_update_usage(expected, new_flavor, sign=1)
self.assertTrue(obj_base.obj_equal_prims(
@ -2543,7 +2554,8 @@ class TestResize(BaseTestCase):
return_value=mig_context_obj),
mock.patch('nova.objects.Instance.save'),
) as (alloc_mock, create_mig_mock, ctxt_mock, inst_save_mock):
self.rt.resize_claim(ctx, instance, new_flavor, _NODENAME, None)
self.rt.resize_claim(ctx, instance, new_flavor, _NODENAME,
None, self.allocations)
pci_claim_mock.assert_called_once_with(ctx, pci_req_mock.return_value,
None)
@ -2723,8 +2735,10 @@ class TestResize(BaseTestCase):
side_effect=[mig_context_obj1, mig_context_obj2]),
mock.patch('nova.objects.Instance.save'),
) as (create_mig_mock, ctxt_mock, inst_save_mock):
self.rt.resize_claim(ctx, instance1, flavor1, _NODENAME, None)
self.rt.resize_claim(ctx, instance2, flavor2, _NODENAME, None)
self.rt.resize_claim(ctx, instance1, flavor1, _NODENAME,
None, self.allocations)
self.rt.resize_claim(ctx, instance2, flavor2, _NODENAME,
None, self.allocations)
cn = self.rt.compute_nodes[_NODENAME]
self.assertTrue(obj_base.obj_equal_prims(expected, cn))
self.assertEqual(2, len(self.rt.tracked_migrations),
@ -2814,7 +2828,7 @@ class TestRebuild(BaseTestCase):
mock.patch('nova.objects.Migration.save'),
mock.patch('nova.objects.Instance.save'),
) as (mig_save_mock, inst_save_mock):
self.rt.rebuild_claim(ctx, instance, _NODENAME,
self.rt.rebuild_claim(ctx, instance, _NODENAME, self.allocations,
migration=migration)
self.assertEqual(_HOSTNAME, migration.dest_compute)

View File

@ -310,7 +310,7 @@ class ShelveComputeManagerTestCase(test_compute.BaseTestCase):
def fake_delete(self2, ctxt, image_id):
self.deleted_image_id = image_id
def fake_claim(context, instance, node, limits):
def fake_claim(context, instance, node, allocations, limits):
instance.host = self.compute.host
requests = objects.InstancePCIRequests(requests=[])
return claims.Claim(context, instance, test_compute.NODENAME,
@ -420,7 +420,7 @@ class ShelveComputeManagerTestCase(test_compute.BaseTestCase):
tracking = {'last_state': instance.task_state}
def fake_claim(context, instance, node, limits):
def fake_claim(context, instance, node, allocations, limits):
instance.host = self.compute.host
requests = objects.InstancePCIRequests(requests=[])
return claims.Claim(context, instance, test_compute.NODENAME,
@ -468,7 +468,7 @@ class ShelveComputeManagerTestCase(test_compute.BaseTestCase):
self.compute.host)
mock_instance_claim.assert_called_once_with(self.context, instance,
test_compute.NODENAME,
limits)
{}, limits)
mock_spawn.assert_called_once_with(self.context, instance,
test.MatchType(objects.ImageMeta),
injected_files=[], admin_password=None,
@ -513,7 +513,7 @@ class ShelveComputeManagerTestCase(test_compute.BaseTestCase):
tracking = {'last_state': instance.task_state}
def fake_claim(context, instance, node, limits):
def fake_claim(context, instance, node, allocations, limits):
instance.host = self.compute.host
instance.node = node
requests = objects.InstancePCIRequests(requests=[])
@ -555,7 +555,7 @@ class ShelveComputeManagerTestCase(test_compute.BaseTestCase):
self.compute.host)
mock_instance_claim.assert_called_once_with(self.context, instance,
test_compute.NODENAME,
limits)
{}, limits)
mock_spawn.assert_called_once_with(
self.context, instance, test.MatchType(objects.ImageMeta),
injected_files=[], admin_password=None,