Skip to content

Commit d54bd31

Browse files
Balazs GibizerGabriel Silva Trevisan
authored andcommitted
[rt] Apply migration context for incoming migrations
There is a race condition between an incoming resize and an update_available_resource periodic in the resource tracker. The race window starts when the resize_instance RPC finishes and ends when the finish_resize compute RPC finally applies the migration context on the instance. In the race window, if the update_available_resource periodic is run on the destination node, then it will see the instance as being tracked on this host as the instance.node is already pointing to the dest. But the instance.numa_topology still points to the source host topology as the migration context is not applied yet. This leads to CPU pinning error if the source topology does not fit to the dest topology. Also it stops the periodic task and leaves the tracker in an inconsistent state. The inconsistent state only cleanup up after the periodic is run outside of the race window. This patch applies the migration context temporarily to the specific instances during the periodic to keep resource accounting correct. Change-Id: Icaad155e22c9e2d86e464a0deb741c73f0dfb28a Closes-Bug: #1953359 Closes-Bug: #1952915 (cherry picked from commit 32c1044) (cherry picked from commit 1235dc3) (cherry picked from commit 5f2f283)
1 parent 8d44874 commit d54bd31

File tree

2 files changed

+40
-24
lines changed

2 files changed

+40
-24
lines changed

nova/compute/resource_tracker.py

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -933,14 +933,41 @@ def _update_available_resource(self, context, resources, startup=False):
933933
'flavor', 'migration_context',
934934
'resources'])
935935

936-
# Now calculate usage based on instance utilization:
937-
instance_by_uuid = self._update_usage_from_instances(
938-
context, instances, nodename)
939-
940936
# Grab all in-progress migrations and error migrations:
941937
migrations = objects.MigrationList.get_in_progress_and_error(
942938
context, self.host, nodename)
943939

940+
# Check for tracked instances with in-progress, incoming, but not
941+
# finished migrations. For those instance the migration context
942+
# is not applied yet (it will be during finish_resize when the
943+
# migration goes to finished state). We need to manually and
944+
# temporary apply the migration context here when the resource usage is
945+
# updated. See bug 1953359 for more details.
946+
instance_by_uuid = {instance.uuid: instance for instance in instances}
947+
for migration in migrations:
948+
if (
949+
migration.instance_uuid in instance_by_uuid and
950+
migration.dest_compute == self.host and
951+
migration.dest_node == nodename
952+
):
953+
# we does not check for the 'post-migrating' migration status
954+
# as applying the migration context for an instance already
955+
# in finished migration status is a no-op anyhow.
956+
instance = instance_by_uuid[migration.instance_uuid]
957+
LOG.debug(
958+
'Applying migration context for instance %s as it has an '
959+
'incoming, in-progress migration %s. '
960+
'Migration status is %s',
961+
migration.instance_uuid, migration.uuid, migration.status
962+
)
963+
# It is OK not to revert the migration context at the end of
964+
# the periodic as the instance is not saved during the periodic
965+
instance.apply_migration_context()
966+
967+
# Now calculate usage based on instance utilization:
968+
instance_by_uuid = self._update_usage_from_instances(
969+
context, instances, nodename)
970+
944971
self._pair_instances_to_migrations(migrations, instance_by_uuid)
945972
self._update_usage_from_migrations(context, migrations, nodename)
946973

nova/tests/functional/libvirt/test_numa_servers.py

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -880,11 +880,11 @@ def fake_finish_resize(*args, **kwargs):
880880
'vCPUs mapping: [(0, 1)]',
881881
log,
882882
)
883-
# But the periodic fails as it tries to apply the source topology
884-
# on the dest. This is bug 1953359.
883+
# We expect that the periodic not fails as bug 1953359 is fixed.
885884
log = self.stdlog.logger.output
886-
self.assertIn('Error updating resources for node compute2', log)
887-
self.assertIn(
885+
self.assertIn('Running periodic for compute (compute2)', log)
886+
self.assertNotIn('Error updating resources for node compute2', log)
887+
self.assertNotIn(
888888
'nova.exception.CPUPinningInvalid: CPU set to pin [0] must be '
889889
'a subset of free CPU set [1]',
890890
log,
@@ -902,27 +902,16 @@ def fake_finish_resize(*args, **kwargs):
902902
new=fake_finish_resize,
903903
):
904904
post = {'migrate': None}
905-
# this is expected to succeed but logs are emitted
906-
# from the racing periodic task. See fake_finish_resize
907-
# for the asserts
905+
# this is expected to succeed
908906
self.admin_api.post_server_action(server['id'], post)
909907

910908
server = self._wait_for_state_change(server, 'VERIFY_RESIZE')
911909

912-
# as the periodic job raced and failed during the resize if we revert
913-
# the instance now then it tries to unpin its cpus from the dest host
914-
# but those was never pinned as the periodic failed. So the unpinning
915-
# will fail too.
910+
# As bug 1953359 is fixed the revert should succeed too
916911
post = {'revertResize': {}}
917-
ex = self.assertRaises(
918-
client.OpenStackApiException,
919-
self.admin_api.post_server_action, server['id'], post
920-
)
921-
# This is still bug 1953359.
922-
self.assertEqual(500, ex.response.status_code)
923-
server = self.api.get_server(server['id'])
924-
self.assertEqual('ERROR', server['status'])
925-
self.assertIn(
912+
self.admin_api.post_server_action(server['id'], post)
913+
self._wait_for_state_change(server, 'ACTIVE')
914+
self.assertNotIn(
926915
'nova.exception.CPUUnpinningInvalid: CPU set to unpin [1] must be '
927916
'a subset of pinned CPU set [0]',
928917
self.stdlog.logger.output,

0 commit comments

Comments
 (0)