@@ -818,6 +818,88 @@ def test_resize_revert_bug_1944759(self):
818
818
self ._assert_pinned_cpus (src_host , 2 )
819
819
self ._assert_pinned_cpus (dst_host , 0 )
820
820
821
+ def test_resize_dedicated_policy_race_on_dest_bug_1953359 (self ):
822
+
823
+ self .flags (cpu_dedicated_set = '0-2' , cpu_shared_set = None ,
824
+ group = 'compute' )
825
+ self .flags (vcpu_pin_set = None )
826
+
827
+ host_info = fakelibvirt .HostInfo (cpu_nodes = 1 , cpu_sockets = 1 ,
828
+ cpu_cores = 2 , cpu_threads = 1 ,
829
+ kB_mem = 15740000 )
830
+ self .start_compute (host_info = host_info , hostname = 'compute1' )
831
+
832
+ extra_spec = {
833
+ 'hw:cpu_policy' : 'dedicated' ,
834
+ }
835
+ flavor_id = self ._create_flavor (vcpu = 1 , extra_spec = extra_spec )
836
+ expected_usage = {'DISK_GB' : 20 , 'MEMORY_MB' : 2048 , 'PCPU' : 1 }
837
+
838
+ server = self ._run_build_test (flavor_id , expected_usage = expected_usage )
839
+
840
+ inst = objects .Instance .get_by_uuid (self .ctxt , server ['id' ])
841
+ self .assertEqual (1 , len (inst .numa_topology .cells ))
842
+ # assert that the pcpu 0 is used on compute1
843
+ self .assertEqual ({'0' : 0 }, inst .numa_topology .cells [0 ].cpu_pinning_raw )
844
+
845
+ # start another compute with the same config
846
+ self .start_compute (host_info = host_info , hostname = 'compute2' )
847
+
848
+ # boot another instance but now on compute2 so that it occupies the
849
+ # pcpu 0 on compute2
850
+ # NOTE(gibi): _run_build_test cannot be used here as it assumes only
851
+ # compute1 exists
852
+ server2 = self ._create_server (
853
+ flavor_id = flavor_id ,
854
+ host = 'compute2' ,
855
+ )
856
+ inst2 = objects .Instance .get_by_uuid (self .ctxt , server2 ['id' ])
857
+ self .assertEqual (1 , len (inst2 .numa_topology .cells ))
858
+ # assert that the pcpu 0 is used
859
+ self .assertEqual (
860
+ {'0' : 0 }, inst2 .numa_topology .cells [0 ].cpu_pinning_raw )
861
+
862
+ # migrate the first instance from compute1 to compute2 but stop
863
+ # migrating at the start of finish_resize. Then start a racing periodic
864
+ # update_available_resources.
865
+
866
+ def fake_finish_resize (* args , ** kwargs ):
867
+ # start a racing update_available_resource periodic
868
+ self ._run_periodics ()
869
+ # we expect it that CPU pinning fails on the destination node
870
+ # as the resource_tracker will use the source node numa_topology
871
+ # and that does not fit to the dest node as pcpu 0 in the dest
872
+ # is already occupied.
873
+
874
+ # TODO(stephenfin): The mock of 'migrate_disk_and_power_off' should
875
+ # probably be less...dumb
876
+ with mock .patch ('nova.virt.libvirt.driver.LibvirtDriver'
877
+ '.migrate_disk_and_power_off' , return_value = '{}' ):
878
+ with mock .patch (
879
+ 'nova.compute.manager.ComputeManager.finish_resize'
880
+ ) as mock_finish_resize :
881
+ mock_finish_resize .side_effect = fake_finish_resize
882
+ post = {'migrate' : None }
883
+ self .admin_api .post_server_action (server ['id' ], post )
884
+
885
+ log = self .stdlog .logger .output
886
+ # The resize_claim correctly calculates that the inst1 should be pinned
887
+ # to pcpu id 1 instead of 0
888
+ self .assertIn (
889
+ 'Computed NUMA topology CPU pinning: usable pCPUs: [[1]], '
890
+ 'vCPUs mapping: [(0, 1)]' ,
891
+ log ,
892
+ )
893
+ # But the periodic fails as it tries to apply the source topology on
894
+ # the dest. This is bug 1953359.
895
+ log = self .stdlog .logger .output
896
+ self .assertIn ('Error updating resources for node compute2' , log )
897
+ self .assertIn (
898
+ 'nova.exception.CPUPinningInvalid: CPU set to pin [0] must be '
899
+ 'a subset of free CPU set [1]' ,
900
+ log ,
901
+ )
902
+
821
903
822
904
class NUMAServerTestWithCountingQuotaFromPlacement (NUMAServersTest ):
823
905
0 commit comments