@@ -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