@@ -615,6 +615,69 @@ def test_get_by_instance_uuid(self, mock_get_ig, get_by_uuid):
615
615
self .assertIsInstance (req_obj .instance_group , objects .InstanceGroup )
616
616
self .assertEqual ('fresh' , req_obj .instance_group .name )
617
617
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
+
618
681
def _check_update_primitive (self , req_obj , changes ):
619
682
self .assertEqual (req_obj .instance_uuid , changes ['instance_uuid' ])
620
683
serialized_obj = objects .RequestSpec .obj_from_primitive (
0 commit comments