Skip to content

Commit 7f6ec8c

Browse files
author
Balazs Gibizer
committed
Migrate RequestSpec.numa_topology to use pcpuset
When the InstanceNUMATopology OVO has changed in I901fbd7df00e45196395ff4c69e7b8aa3359edf6 to separately track pcpus from vcpus a data migration was added. This data migration is triggered when the InstanceNUMATopology object is loaded from the instance_extra table. However that patch is missed the fact that the InstanceNUMATopology object can be loaded from the request_spec table as well. So InstanceNUMATopology object in RequestSpec are not migrated. This could lead to errors in the scheduler when such RequestSpec object is used for scheduling (e.g. during a migration of a pre Victoria instance with cpu pinning) This patch adds the missing data migration. Change-Id: I812d720555bdf008c83cae3d81541a37bd99e594 Closes-Bug: #1952941 (cherry picked from commit e853bb5)
1 parent d860615 commit 7f6ec8c

File tree

4 files changed

+47
-42
lines changed

4 files changed

+47
-42
lines changed

nova/objects/instance_numa.py

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,10 @@ def obj_from_db_obj(cls, context, instance_uuid, db_obj):
166166

167167
if 'nova_object.name' in primitive:
168168
obj = cls.obj_from_primitive(primitive)
169-
cls._migrate_legacy_dedicated_instance_cpuset(
170-
context, instance_uuid, obj)
169+
updated = cls._migrate_legacy_dedicated_instance_cpuset(obj)
170+
if updated:
171+
cls._save_migrated_cpuset_to_instance_extra(
172+
context, obj, instance_uuid)
171173
else:
172174
obj = cls._migrate_legacy_object(context, instance_uuid, primitive)
173175

@@ -176,13 +178,14 @@ def obj_from_db_obj(cls, context, instance_uuid, db_obj):
176178
# TODO(huaqiang): Remove after Wallaby once we are sure these objects have
177179
# been loaded at least once.
178180
@classmethod
179-
def _migrate_legacy_dedicated_instance_cpuset(cls, context, instance_uuid,
180-
obj):
181+
def _migrate_legacy_dedicated_instance_cpuset(cls, obj):
181182
# NOTE(huaqiang): We may meet some topology object with the old version
182183
# 'InstanceNUMACell' cells, in that case, the 'dedicated' CPU is kept
183184
# in 'InstanceNUMACell.cpuset' field, but it should be kept in
184185
# 'InstanceNUMACell.pcpuset' field since Victoria. Making an upgrade
185-
# and persisting to database.
186+
# here but letting the caller persist the result if needed as we
187+
# don't know which table the InstanceNUMACell is coming from. It can
188+
# come from instance_extra or request_spec too.
186189
update_db = False
187190
for cell in obj.cells:
188191
if len(cell.cpuset) == 0:
@@ -194,14 +197,20 @@ def _migrate_legacy_dedicated_instance_cpuset(cls, context, instance_uuid,
194197
cell.pcpuset = cell.cpuset
195198
cell.cpuset = set()
196199
update_db = True
200+
return update_db
197201

198-
if update_db:
199-
db_obj = jsonutils.dumps(obj.obj_to_primitive())
200-
values = {
201-
'numa_topology': db_obj,
202-
}
203-
db.instance_extra_update_by_uuid(context, instance_uuid,
204-
values)
202+
# TODO(huaqiang): Remove after Yoga once we are sure these objects have
203+
# been loaded at least once.
204+
@classmethod
205+
def _save_migrated_cpuset_to_instance_extra(
206+
cls, context, obj, instance_uuid
207+
):
208+
db_obj = jsonutils.dumps(obj.obj_to_primitive())
209+
values = {
210+
'numa_topology': db_obj,
211+
}
212+
db.instance_extra_update_by_uuid(
213+
context, instance_uuid, values)
205214

206215
# TODO(stephenfin): Remove in X or later, once this has bedded in
207216
@classmethod

nova/objects/request_spec.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,8 @@ def ensure_network_information(self, instance):
596596
@staticmethod
597597
def _from_db_object(context, spec, db_spec):
598598
spec_obj = spec.obj_from_primitive(jsonutils.loads(db_spec['spec']))
599+
data_migrated = False
600+
599601
for key in spec.fields:
600602
# Load these from the db model not the serialized object within,
601603
# though they should match.
@@ -616,6 +618,13 @@ def _from_db_object(context, spec, db_spec):
616618
# fields. If they are not set, set None.
617619
if not spec.obj_attr_is_set(key):
618620
setattr(spec, key, None)
621+
elif key == "numa_topology":
622+
if key in spec_obj:
623+
spec.numa_topology = spec_obj.numa_topology
624+
if spec.numa_topology:
625+
data_migrated = objects.InstanceNUMATopology.\
626+
_migrate_legacy_dedicated_instance_cpuset(
627+
spec.numa_topology)
619628
elif key in spec_obj:
620629
setattr(spec, key, getattr(spec_obj, key))
621630
spec._context = context
@@ -637,6 +646,9 @@ def _from_db_object(context, spec, db_spec):
637646
# NOTE(danms): Instance group may have been deleted
638647
spec.instance_group = None
639648

649+
if data_migrated:
650+
spec.save()
651+
640652
spec.obj_reset_changes()
641653
return spec
642654

nova/tests/unit/objects/test_request_spec.py

Lines changed: 5 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -615,29 +615,12 @@ def test_get_by_instance_uuid(self, mock_get_ig, get_by_uuid):
615615
self.assertIsInstance(req_obj.instance_group, objects.InstanceGroup)
616616
self.assertEqual('fresh', req_obj.instance_group.name)
617617

618-
# FIXME(gibi): This is bug 1952941. When the cpuset -> pcpuset data
619-
# migration was added to InstanceNUMATopology it was missed that such
620-
# object is not only hydrated via
621-
# InstanceNUMATopology.get_by_instance_uuid() but also hydrated by
622-
# RequestSpec.get_by_instance_uuid() indirectly. However the
623-
# latter code patch does not call InstanceNUMATopology.obj_from_db_obj()
624-
# that triggers the data migration via
625-
# InstanceNUMATopology._migrate_legacy_dedicated_instance_cpuset.
626-
# This causes that when the new nova code loads an old RequestSpec object
627-
# from the DB (e.g. during migration of an instance) the
628-
# InstanceNUMATopology in the RequestSpec will not be migrated to the new
629-
# object version and it will lead to errors when the pcpuset field is read
630-
# during scheduling.
631-
@mock.patch(
632-
'nova.objects.instance_numa.InstanceNUMATopology.'
633-
'_migrate_legacy_dedicated_instance_cpuset',
634-
new=mock.NonCallableMock()
635-
)
618+
@mock.patch('nova.objects.request_spec.RequestSpec.save')
636619
@mock.patch.object(
637620
request_spec.RequestSpec, '_get_by_instance_uuid_from_db')
638621
@mock.patch('nova.objects.InstanceGroup.get_by_uuid')
639622
def test_get_by_instance_uuid_numa_topology_migration(
640-
self, mock_get_ig, get_by_uuid
623+
self, mock_get_ig, get_by_uuid, mock_save
641624
):
642625
# Simulate a pre-Victoria RequestSpec where the pcpuset field is not
643626
# defined for the embedded InstanceNUMACell objects but the cpu_policy
@@ -665,18 +648,10 @@ def test_get_by_instance_uuid_numa_topology_migration(
665648
self.context, fake_spec['instance_uuid'])
666649

667650
self.assertEqual(2, len(req_obj.numa_topology.cells))
651+
self.assertEqual({1, 2}, req_obj.numa_topology.cells[0].pcpuset)
652+
self.assertEqual({3, 4}, req_obj.numa_topology.cells[1].pcpuset)
668653

669-
# This is bug 1952941 as the pcpuset is not defined in object as the
670-
# object is not migrated
671-
ex = self.assertRaises(
672-
NotImplementedError,
673-
lambda: req_obj.numa_topology.cells[0].pcpuset
674-
)
675-
self.assertIn("Cannot load 'pcpuset' in the base class", str(ex))
676-
677-
# This is the expected behavior
678-
# self.assertEqual({1, 2}, req_obj.numa_topology.cells[0].pcpuset)
679-
# self.assertEqual({3, 4}, req_obj.numa_topology.cells[1].pcpuset)
654+
mock_save.assert_called_once()
680655

681656
def _check_update_primitive(self, req_obj, changes):
682657
self.assertEqual(req_obj.instance_uuid, changes['instance_uuid'])
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
fixes:
3+
- |
4+
The `bug 1952941`_ is fixed where a pre-Victoria server with pinned
5+
CPUs cannot be migrated or evacuated after the cloud is upgraded to
6+
Victoria or newer as the scheduling fails with
7+
``NotImplementedError: Cannot load 'pcpuset'`` error.
8+
9+
.. _bug 1952941: https://bugs.launchpad.net/nova/+bug/1952941

0 commit comments

Comments
 (0)