@@ -611,6 +611,69 @@ def test_get_by_instance_uuid(self, mock_get_ig, get_by_uuid):
611611 self .assertIsInstance (req_obj .instance_group , objects .InstanceGroup )
612612 self .assertEqual ('fresh' , req_obj .instance_group .name )
613613
614+ # FIXME(gibi): This is bug 1952941. When the cpuset -> pcpuset data
615+ # migration was added to InstanceNUMATopology it was missed that such
616+ # object is not only hydrated via
617+ # InstanceNUMATopology.get_by_instance_uuid() but also hydrated by
618+ # RequestSpec.get_by_instance_uuid() indirectly. However the
619+ # latter code patch does not call InstanceNUMATopology.obj_from_db_obj()
620+ # that triggers the data migration via
621+ # InstanceNUMATopology._migrate_legacy_dedicated_instance_cpuset.
622+ # This causes that when the new nova code loads an old RequestSpec object
623+ # from the DB (e.g. during migration of an instance) the
624+ # InstanceNUMATopology in the RequestSpec will not be migrated to the new
625+ # object version and it will lead to errors when the pcpuset field is read
626+ # during scheduling.
627+ @mock .patch (
628+ 'nova.objects.instance_numa.InstanceNUMATopology.'
629+ '_migrate_legacy_dedicated_instance_cpuset' ,
630+ new = mock .NonCallableMock ()
631+ )
632+ @mock .patch .object (
633+ request_spec .RequestSpec , '_get_by_instance_uuid_from_db' )
634+ @mock .patch ('nova.objects.InstanceGroup.get_by_uuid' )
635+ def test_get_by_instance_uuid_numa_topology_migration (
636+ self , mock_get_ig , get_by_uuid
637+ ):
638+ # Simulate a pre-Victoria RequestSpec where the pcpuset field is not
639+ # defined for the embedded InstanceNUMACell objects but the cpu_policy
640+ # is dedicated meaning that cores in cpuset defines pinned cpus. So
641+ # in Victoria or later these InstanceNUMACell objects should be
642+ # translated to hold the cores in the pcpuset field instead.
643+ numa_topology = objects .InstanceNUMATopology (
644+ instance_uuid = uuids .instance_uuid ,
645+ cells = [
646+ objects .InstanceNUMACell (
647+ id = 0 , cpuset = {1 , 2 }, memory = 512 , cpu_policy = "dedicated" ),
648+ objects .InstanceNUMACell (
649+ id = 1 , cpuset = {3 , 4 }, memory = 512 , cpu_policy = "dedicated" ),
650+ ]
651+ )
652+ spec_obj = fake_request_spec .fake_spec_obj ()
653+ spec_obj .numa_topology = numa_topology
654+ fake_spec = fake_request_spec .fake_db_spec (spec_obj )
655+ fake_spec ['instance_uuid' ] = uuids .instance_uuid
656+
657+ get_by_uuid .return_value = fake_spec
658+ mock_get_ig .return_value = objects .InstanceGroup (name = 'fresh' )
659+
660+ req_obj = request_spec .RequestSpec .get_by_instance_uuid (
661+ self .context , fake_spec ['instance_uuid' ])
662+
663+ self .assertEqual (2 , len (req_obj .numa_topology .cells ))
664+
665+ # This is bug 1952941 as the pcpuset is not defined in object as the
666+ # object is not migrated
667+ ex = self .assertRaises (
668+ NotImplementedError ,
669+ lambda : req_obj .numa_topology .cells [0 ].pcpuset
670+ )
671+ self .assertIn ("Cannot load 'pcpuset' in the base class" , str (ex ))
672+
673+ # This is the expected behavior
674+ # self.assertEqual({1, 2}, req_obj.numa_topology.cells[0].pcpuset)
675+ # self.assertEqual({3, 4}, req_obj.numa_topology.cells[1].pcpuset)
676+
614677 def _check_update_primitive (self , req_obj , changes ):
615678 self .assertEqual (req_obj .instance_uuid , changes ['instance_uuid' ])
616679 serialized_obj = objects .RequestSpec .obj_from_primitive (
0 commit comments