@@ -363,6 +363,7 @@ def test_obj_from_db_obj(self):
363
363
fake_topo_obj = copy .deepcopy (fake_topo_obj_w_cell_v1_4 )
364
364
for cell in fake_topo_obj .cells :
365
365
cell .cpu_policy = objects .fields .CPUAllocationPolicy .DEDICATED
366
+ cell .VERSION = '1.4'
366
367
367
368
numa_topology = objects .InstanceNUMATopology .obj_from_db_obj (
368
369
self .context , fake_instance_uuid , fake_topo_obj ._to_json ())
@@ -402,6 +403,7 @@ def test_obj_from_db_obj_no_pinning(self):
402
403
fake_topo_obj = copy .deepcopy (fake_topo_obj_w_cell_v1_4 )
403
404
for cell in fake_topo_obj .cells :
404
405
cell .cpu_policy = objects .fields .CPUAllocationPolicy .SHARED
406
+ cell .VERSION = '1.4'
405
407
406
408
numa_topology = objects .InstanceNUMATopology .obj_from_db_obj (
407
409
self .context , fake_instance_uuid , fake_topo_obj ._to_json ())
@@ -412,7 +414,7 @@ def test_obj_from_db_obj_no_pinning(self):
412
414
self .assertEqual (topo_cell .cpuset , obj_cell .cpuset )
413
415
self .assertEqual (set (), obj_cell .pcpuset )
414
416
415
- def test__migrate_legacy_dedicated_instance_cpuset (self ):
417
+ def test__migrate_legacy_dedicated_instance_cpuset_dedicate_1_4 (self ):
416
418
# Create a topology with a cell on latest version. Would be nice
417
419
# to create one the old 1.4 cell version directly but that is only
418
420
# possible indirectly as done below.
@@ -446,7 +448,118 @@ def test__migrate_legacy_dedicated_instance_cpuset(self):
446
448
# pcpuset
447
449
self .assertEqual (set (), topo_loaded .cells [0 ].cpuset )
448
450
self .assertEqual ({0 , 1 }, topo_loaded .cells [0 ].pcpuset )
449
- # and the version is bumped to 1.6
451
+ # and the version is updated to 1.6
452
+ self .assertEqual ('1.6' , topo_loaded .cells [0 ].VERSION )
453
+
454
+ def test__migrate_legacy_dedicated_instance_cpuset_shared_1_4 (self ):
455
+ # Create a topology with a cell on latest version. Would be nice
456
+ # to create one the old 1.4 cell version directly but that is only
457
+ # possible indirectly as done below.
458
+ topo = objects .InstanceNUMATopology (
459
+ instance_uuid = fake_instance_uuid ,
460
+ cells = [
461
+ objects .InstanceNUMACell (id = 0 , cpuset = {0 , 1 }, pcpuset = set ()),
462
+ ])
463
+ topo .cells [0 ].cpu_policy = objects .fields .CPUAllocationPolicy .SHARED
464
+
465
+ # Use the builtin backlevelling logic to pull it back to old cell
466
+ # version
467
+ topo_with_cell_1_4 = topo .obj_to_primitive (
468
+ target_version = '1.3' , version_manifest = {'InstanceNUMACell' : '1.4' })
469
+
470
+ # Just check that the backlevelling works, and we have a cell with
471
+ # version and data on 1.4 level
472
+ cell_1_4_primitive = topo_with_cell_1_4 ['nova_object.data' ]['cells' ][0 ]
473
+ self .assertEqual ('1.4' , cell_1_4_primitive ['nova_object.version' ])
474
+ self .assertEqual (
475
+ (0 , 1 ), cell_1_4_primitive ['nova_object.data' ]['cpuset' ])
476
+ self .assertNotIn ('pcpuset' , cell_1_4_primitive ['nova_object.data' ])
477
+
478
+ # Now simulate that such old data is loaded from the DB and migrated
479
+ # from 1.4 to 1.6 by the data migration
480
+ topo_loaded = objects .InstanceNUMATopology .obj_from_db_obj (
481
+ self .context , fake_instance_uuid ,
482
+ jsonutils .dumps (topo_with_cell_1_4 ))
483
+
484
+ # In place data migration did not move the data as the cpu_policy is
485
+ # shared
486
+ self .assertEqual ({0 , 1 }, topo_loaded .cells [0 ].cpuset )
487
+ self .assertEqual (set (), topo_loaded .cells [0 ].pcpuset )
488
+ # but the version is updated to 1.6
489
+ self .assertEqual ('1.6' , topo_loaded .cells [0 ].VERSION )
490
+
491
+ def test__migrate_legacy_dedicated_instance_cpuset_dedicated_half_migrated (
492
+ self
493
+ ):
494
+ # Before the fix for https://bugs.launchpad.net/nova/+bug/2097360
495
+ # landed Nova only half migrated the InstanceNUMACell from 1.4 to 1.6
496
+ # by doing the data move but not updating the version string in the DB.
497
+ # This test case ensures that if such migration happened before the fix
498
+ # was deployed then Nova fixed the DB content on the next load as well.
499
+
500
+ # Create a topology with a cell on latest version. Would be nice
501
+ # to create one the old 1.4 cell version directly but that is only
502
+ # possible indirectly as done below.
503
+ topo = objects .InstanceNUMATopology (
504
+ instance_uuid = fake_instance_uuid ,
505
+ cells = [
506
+ objects .InstanceNUMACell (id = 0 , cpuset = set (), pcpuset = {0 , 1 }),
507
+ ])
508
+ topo .cells [0 ].cpu_policy = objects .fields .CPUAllocationPolicy .DEDICATED
509
+
510
+ # simulate the half done migration by pulling back the version string
511
+ # in the primitive form to 1.4 while keeping the data on 1.6 format.
512
+ topo_primitive = topo .obj_to_primitive ()
513
+ cell_primitive = topo_primitive ['nova_object.data' ]['cells' ][0 ]
514
+ self .assertEqual ('1.6' , cell_primitive ['nova_object.version' ])
515
+ cell_primitive ['nova_object.version' ] = '1.4'
516
+
517
+ topo_loaded = objects .InstanceNUMATopology .obj_from_db_obj (
518
+ self .context , fake_instance_uuid , jsonutils .dumps (topo_primitive ))
519
+
520
+ # the data did not change
521
+ self .assertEqual (set (), topo_loaded .cells [0 ].cpuset )
522
+ self .assertEqual ({0 , 1 }, topo_loaded .cells [0 ].pcpuset )
523
+ # but the version is updated to 1.6
524
+ self .assertEqual ('1.6' , topo_loaded .cells [0 ].VERSION )
525
+
526
+ def test__migrate_legacy_dedicated_instance_cpuset_mixed_1_4 (self ):
527
+ # Before the fix for https://bugs.launchpad.net/nova/+bug/2097360
528
+ # landed Nova only half migrated the InstanceNUMACell from 1.4 to 1.6
529
+ # by doing the data move but not updating the version string in the DB.
530
+ # After this the instance is resized to flavor with mixed cpu_policy
531
+ # then there is a good chance that the DB has version string 1.4 but
532
+ # the data is on 1.6 format with the cpu_policy set to mixed.
533
+ # This test case ensures that if such situation happened before the fix
534
+ # was deployed then Nova fixed the DB content on the next load as well.
535
+
536
+ # Create a topology with a cell on latest version. Would be nice
537
+ # to create one the old 1.4 cell version directly but that is only
538
+ # possible indirectly as done below.
539
+ topo = objects .InstanceNUMATopology (
540
+ instance_uuid = fake_instance_uuid ,
541
+ cells = [
542
+ objects .InstanceNUMACell (id = 0 , cpuset = {0 , 1 }, pcpuset = {2 , 3 }),
543
+ ])
544
+ topo .cells [0 ].cpu_policy = objects .fields .CPUAllocationPolicy .MIXED
545
+
546
+ # simulate the half done migration by pulling back the version string
547
+ # in the primitive form to 1.4 while keeping the data on 1.6 format.
548
+ topo_primitive = topo .obj_to_primitive ()
549
+ cell_primitive = topo_primitive ['nova_object.data' ]['cells' ][0 ]
550
+ self .assertEqual ('1.6' , cell_primitive ['nova_object.version' ])
551
+ cell_primitive ['nova_object.version' ] = '1.4'
552
+
553
+ topo_loaded = objects .InstanceNUMATopology .obj_from_db_obj (
554
+ self .context , fake_instance_uuid , jsonutils .dumps (topo_primitive ))
555
+
556
+ # the data did not change
557
+ self .assertEqual ({0 , 1 }, topo_loaded .cells [0 ].cpuset )
558
+ self .assertEqual ({2 , 3 }, topo_loaded .cells [0 ].pcpuset )
559
+ self .assertEqual (
560
+ objects .fields .CPUAllocationPolicy .MIXED ,
561
+ topo_loaded .cells [0 ].cpu_policy )
562
+ # but the version is updated to 1.6
450
563
self .assertEqual ('1.6' , topo_loaded .cells [0 ].VERSION )
451
564
452
565
0 commit comments