Merge "Resource tracker: improve resource tracker periodic task"

This commit is contained in:
Zuul 2018-07-02 12:34:27 +00:00 committed by Gerrit Code Review
commit 503025873c
2 changed files with 43 additions and 38 deletions

View File

@ -685,8 +685,7 @@ class ResourceTracker(object):
self._update_available_resource(context, resources)
def _pair_instances_to_migrations(self, migrations, instances):
instance_by_uuid = {inst.uuid: inst for inst in instances}
def _pair_instances_to_migrations(self, migrations, instance_by_uuid):
for migration in migrations:
try:
migration.instance = instance_by_uuid[migration.instance_uuid]
@ -724,17 +723,19 @@ class ResourceTracker(object):
'flavor', 'migration_context'])
# Now calculate usage based on instance utilization:
self._update_usage_from_instances(context, instances, nodename)
instance_by_uuid = self._update_usage_from_instances(
context, instances, nodename)
# Grab all in-progress migrations:
migrations = objects.MigrationList.get_in_progress_by_host_and_node(
context, self.host, nodename)
self._pair_instances_to_migrations(migrations, instances)
self._pair_instances_to_migrations(migrations, instance_by_uuid)
self._update_usage_from_migrations(context, migrations, nodename)
self._remove_deleted_instances_allocations(
context, self.compute_nodes[nodename], migrations)
context, self.compute_nodes[nodename], migrations,
instance_by_uuid)
# Detect and account for orphaned instances that may exist on the
# hypervisor, but are not in the DB:
@ -1228,7 +1229,7 @@ class ResourceTracker(object):
msg_allocation_refresh += (
"Will auto-correct allocations to handle "
"Ocata-style assumptions.")
instance_by_uuid = {}
for instance in instances:
if instance.vm_state not in vm_states.ALLOW_RESOURCE_REMOVAL:
if msg_allocation_refresh:
@ -1236,9 +1237,11 @@ class ResourceTracker(object):
msg_allocation_refresh = False
self._update_usage_from_instance(context, instance, nodename,
require_allocation_refresh=require_allocation_refresh)
instance_by_uuid[instance.uuid] = instance
return instance_by_uuid
def _remove_deleted_instances_allocations(self, context, cn,
migrations):
migrations, instance_by_uuid):
migration_uuids = [migration.uuid for migration in migrations
if 'uuid' in migration]
# NOTE(jaypipes): All of this code sucks. It's basically dealing with
@ -1264,22 +1267,25 @@ class ResourceTracker(object):
# We know these are instances now, so proceed
instance_uuid = consumer_uuid
try:
instance = objects.Instance.get_by_uuid(read_deleted_context,
instance_uuid,
expected_attrs=[])
except exception.InstanceNotFound:
# The instance isn't even in the database. Either the scheduler
# _just_ created an allocation for it and we're racing with the
# creation in the cell database, or the instance was deleted
# and fully archived before we got a chance to run this. The
# former is far more likely than the latter. Avoid deleting
# allocations for a building instance here.
LOG.info("Instance %(uuid)s has allocations against this "
"compute host but is not found in the database.",
{'uuid': instance_uuid},
exc_info=False)
continue
instance = instance_by_uuid.get(instance_uuid)
if not instance:
try:
instance = objects.Instance.get_by_uuid(
read_deleted_context, consumer_uuid,
expected_attrs=[])
except exception.InstanceNotFound:
# The instance isn't even in the database. Either the
# scheduler _just_ created an allocation for it and we're
# racing with the creation in the cell database, or the
# instance was deleted and fully archived before we got a
# chance to run this. The former is far more likely than
# the latter. Avoid deleting allocations for a building
# instance here.
LOG.info("Instance %(uuid)s has allocations against this "
"compute host but is not found in the database.",
{'uuid': instance_uuid},
exc_info=False)
continue
if instance.deleted:
# The instance is gone, so we definitely want to remove

View File

@ -2666,7 +2666,7 @@ class TestUpdateUsageFromInstance(BaseTestCase):
cn = self.rt.compute_nodes[_NODENAME]
ctx = mock.MagicMock()
# Call the method.
self.rt._remove_deleted_instances_allocations(ctx, cn, [])
self.rt._remove_deleted_instances_allocations(ctx, cn, [], {})
# Only one call should be made to delete allocations, and that should
# be for the first instance created above
rc.delete_allocation_for_instance.assert_called_once_with(
@ -2691,7 +2691,7 @@ class TestUpdateUsageFromInstance(BaseTestCase):
cn = self.rt.compute_nodes[_NODENAME]
ctx = mock.MagicMock()
# Call the method.
self.rt._remove_deleted_instances_allocations(ctx, cn, [])
self.rt._remove_deleted_instances_allocations(ctx, cn, [], {})
# Instance wasn't found in the database at all, so the allocation
# should not have been deleted
self.assertFalse(rc.delete_allocation_for_instance.called)
@ -2713,7 +2713,8 @@ class TestUpdateUsageFromInstance(BaseTestCase):
ctx = mock.MagicMock()
# Call the method.
self.rt._remove_deleted_instances_allocations(
ctx, cn, [mig])
ctx, cn, [mig], {uuids.migration:
objects.Instance(uuid=uuids.imigration)})
# Only one call should be made to delete allocations, and that should
# be for the first instance created above
rc.delete_allocation_for_instance.assert_called_once_with(
@ -2728,18 +2729,14 @@ class TestUpdateUsageFromInstance(BaseTestCase):
rc.get_allocations_for_resource_provider = mock.MagicMock(
return_value=allocs)
rc.delete_allocation_for_instance = mock.MagicMock()
def get_by_uuid(ctx, inst_uuid, expected_attrs=None):
ret = _INSTANCE_FIXTURES[0].obj_clone()
ret.uuid = inst_uuid
ret.host = None # This indicates the instance is being scheduled
return ret
mock_inst_get.side_effect = get_by_uuid
instance_by_uuid = {uuids.scheduled:
objects.Instance(uuid=uuids.scheduled,
deleted=False, host=None)}
cn = self.rt.compute_nodes[_NODENAME]
ctx = mock.MagicMock()
# Call the method.
self.rt._remove_deleted_instances_allocations(ctx, cn, [])
self.rt._remove_deleted_instances_allocations(ctx, cn, [],
instance_by_uuid)
# Scheduled instances should not have their allocations removed
rc.delete_allocation_for_instance.assert_not_called()
@ -2767,7 +2764,7 @@ class TestUpdateUsageFromInstance(BaseTestCase):
cn = self.rt.compute_nodes[_NODENAME]
ctx = mock.MagicMock()
self.rt._remove_deleted_instances_allocations(ctx, cn, [])
self.rt._remove_deleted_instances_allocations(ctx, cn, [], mock.ANY)
mock_delete_allocs.assert_not_called()
def test_remove_deleted_instances_allocations_known_instance(self):
@ -2792,7 +2789,8 @@ class TestUpdateUsageFromInstance(BaseTestCase):
cn = self.rt.compute_nodes[_NODENAME]
ctx = mock.MagicMock()
# Call the method.
self.rt._remove_deleted_instances_allocations(ctx, cn, [])
self.rt._remove_deleted_instances_allocations(ctx, cn, [],
self.rt.tracked_instances)
# We don't delete the allocation because the node is tracking the
# instance and has allocations for it.
rc.delete_allocation_for_instance.assert_not_called()
@ -2826,7 +2824,8 @@ class TestUpdateUsageFromInstance(BaseTestCase):
cn = self.rt.compute_nodes[_NODENAME]
ctx = mock.MagicMock()
# Call the method.
self.rt._remove_deleted_instances_allocations(ctx, cn, [])
self.rt._remove_deleted_instances_allocations(
ctx, cn, [], self.rt.tracked_instances)
# We don't delete the allocation because we're not sure what to do.
# NOTE(mriedem): This is not actually the behavior we want. This is
# testing the current behavior but in the future when we get smart