Skip to content

Commit d860615

Browse files
author
Balazs Gibizer
committed
Reproduce bug 1952941
The added unit test proves that pre-Victoria RequestSpec objects describing a cpu pinned Instance are not migrated to a proper format in Victoria or newer. Related-Bug: #1952941 Change-Id: I672af45a1d1c7fb428b1c4983d4f856852829fb9 (cherry picked from commit 05e8977)
1 parent a79c26e commit d860615

File tree

2 files changed

+69
-5
lines changed

2 files changed

+69
-5
lines changed

nova/tests/unit/fake_request_spec.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,15 @@
5757
PCI_REQUESTS.obj_reset_changes(recursive=True)
5858

5959

60-
def fake_db_spec():
61-
req_obj = fake_spec_obj()
60+
def fake_db_spec(spec_obj=None):
61+
if not spec_obj:
62+
spec_obj = fake_spec_obj()
6263
# NOTE(takashin): There is not 'retry' information in the DB table.
63-
del req_obj.retry
64+
del spec_obj.retry
6465
db_request_spec = {
6566
'id': 1,
66-
'instance_uuid': req_obj.instance_uuid,
67-
'spec': jsonutils.dumps(req_obj.obj_to_primitive()),
67+
'instance_uuid': spec_obj.instance_uuid,
68+
'spec': jsonutils.dumps(spec_obj.obj_to_primitive()),
6869
}
6970

7071
return db_request_spec

nova/tests/unit/objects/test_request_spec.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,69 @@ 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+
)
636+
@mock.patch.object(
637+
request_spec.RequestSpec, '_get_by_instance_uuid_from_db')
638+
@mock.patch('nova.objects.InstanceGroup.get_by_uuid')
639+
def test_get_by_instance_uuid_numa_topology_migration(
640+
self, mock_get_ig, get_by_uuid
641+
):
642+
# Simulate a pre-Victoria RequestSpec where the pcpuset field is not
643+
# defined for the embedded InstanceNUMACell objects but the cpu_policy
644+
# is dedicated meaning that cores in cpuset defines pinned cpus. So
645+
# in Victoria or later these InstanceNUMACell objects should be
646+
# translated to hold the cores in the pcpuset field instead.
647+
numa_topology = objects.InstanceNUMATopology(
648+
instance_uuid=uuids.instance_uuid,
649+
cells=[
650+
objects.InstanceNUMACell(
651+
id=0, cpuset={1, 2}, memory=512, cpu_policy="dedicated"),
652+
objects.InstanceNUMACell(
653+
id=1, cpuset={3, 4}, memory=512, cpu_policy="dedicated"),
654+
]
655+
)
656+
spec_obj = fake_request_spec.fake_spec_obj()
657+
spec_obj.numa_topology = numa_topology
658+
fake_spec = fake_request_spec.fake_db_spec(spec_obj)
659+
fake_spec['instance_uuid'] = uuids.instance_uuid
660+
661+
get_by_uuid.return_value = fake_spec
662+
mock_get_ig.return_value = objects.InstanceGroup(name='fresh')
663+
664+
req_obj = request_spec.RequestSpec.get_by_instance_uuid(
665+
self.context, fake_spec['instance_uuid'])
666+
667+
self.assertEqual(2, len(req_obj.numa_topology.cells))
668+
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)
680+
618681
def _check_update_primitive(self, req_obj, changes):
619682
self.assertEqual(req_obj.instance_uuid, changes['instance_uuid'])
620683
serialized_obj = objects.RequestSpec.obj_from_primitive(

0 commit comments

Comments
 (0)