Browse Source

Fix loading things in instance_extra for old instances

If we don't have db_inst['extra'] then we can't load those things. We
should just set them to None instead of exploding.

Change-Id: I2ace62158faaa0b6a7df3c32f2cb9f235d178013
Closes-Bug: #1446082
tags/12.0.0a0
Dan Smith 4 years ago
parent
commit
1bfb65d5ac
2 changed files with 57 additions and 7 deletions
  1. 25
    7
      nova/objects/instance.py
  2. 32
    0
      nova/tests/unit/objects/test_instance.py

+ 25
- 7
nova/objects/instance.py View File

@@ -450,8 +450,9 @@ class Instance(base.NovaPersistentObject, base.NovaObject,
450 450
         if flavor_implied:
451 451
             # This instance is from before flavors were migrated out of
452 452
             # system_metadata. Make sure that we honor that.
453
-            if db_inst['extra']['flavor'] is not None:
454
-                self._flavor_from_db(db_inst['extra']['flavor'])
453
+            instance_extra = db_inst.get('extra') or {}
454
+            if instance_extra.get('flavor') is not None:
455
+                self._flavor_from_db(instance_extra['flavor'])
455 456
                 sysmeta = self.system_metadata
456 457
                 flavors.save_flavor_info(sysmeta, self.flavor)
457 458
                 del self.flavor
@@ -493,6 +494,13 @@ class Instance(base.NovaPersistentObject, base.NovaObject,
493 494
             else:
494 495
                 instance[field] = db_inst[field]
495 496
 
497
+        # NOTE(danms): We can be called with a dict instead of a
498
+        # SQLAlchemy object, so we have to be careful here
499
+        if hasattr(db_inst, '__dict__'):
500
+            have_extra = 'extra' in db_inst.__dict__ and db_inst['extra']
501
+        else:
502
+            have_extra = 'extra' in db_inst and db_inst['extra']
503
+
496 504
         if 'metadata' in expected_attrs:
497 505
             instance['metadata'] = utils.instance_meta(db_inst)
498 506
         if 'system_metadata' in expected_attrs:
@@ -502,13 +510,23 @@ class Instance(base.NovaPersistentObject, base.NovaObject,
502 510
                 objects.InstanceFault.get_latest_for_instance(
503 511
                     context, instance.uuid))
504 512
         if 'numa_topology' in expected_attrs:
505
-            instance._load_numa_topology(
506
-                db_inst.get('extra').get('numa_topology'))
513
+            if have_extra:
514
+                instance._load_numa_topology(
515
+                    db_inst['extra'].get('numa_topology'))
516
+            else:
517
+                instance.numa_topology = None
507 518
         if 'pci_requests' in expected_attrs:
508
-            instance._load_pci_requests(
509
-                db_inst.get('extra').get('pci_requests'))
519
+            if have_extra:
520
+                instance._load_pci_requests(
521
+                    db_inst['extra'].get('pci_requests'))
522
+            else:
523
+                instance.pci_requests = None
510 524
         if 'vcpu_model' in expected_attrs:
511
-            instance._load_vcpu_model(db_inst.get('extra').get('vcpu_model'))
525
+            if have_extra:
526
+                instance._load_vcpu_model(
527
+                    db_inst['extra'].get('vcpu_model'))
528
+            else:
529
+                instance.vcpu_model = None
512 530
         if 'ec2_ids' in expected_attrs:
513 531
             instance._load_ec2_ids()
514 532
         if 'info_cache' in expected_attrs:

+ 32
- 0
nova/tests/unit/objects/test_instance.py View File

@@ -1269,6 +1269,38 @@ class _TestInstanceObject(object):
1269 1269
         self.assertTrue(inst.obj_attr_is_set('flavor'))
1270 1270
         self.assertEqual(flavor.flavorid, inst.flavor.flavorid)
1271 1271
 
1272
+    def test_without_extra_record(self):
1273
+        flavor = flavors.get_default_flavor()
1274
+        db_inst = fake_instance.fake_db_instance()
1275
+        db_inst['system_metadata'] = flavors.save_flavor_info({}, flavor)
1276
+        del db_inst['extra']
1277
+        with mock.patch('nova.db.instance_get_by_uuid') as mock_get:
1278
+            mock_get.return_value = db_inst
1279
+            inst = objects.Instance.get_by_uuid(
1280
+                self.context, uuid='foo',
1281
+                expected_attrs=['numa_topology', 'pci_requests', 'vcpu_model',
1282
+                                'flavor'])
1283
+            for field in ('numa_topology', 'pci_requests', 'vcpu_model'):
1284
+                self.assertTrue(inst.obj_attr_is_set(field))
1285
+                self.assertIsNone(getattr(inst, field))
1286
+            self.assertTrue(inst.obj_attr_is_set('flavor'))
1287
+
1288
+    def test_with_null_extra_record(self):
1289
+        flavor = flavors.get_default_flavor()
1290
+        db_inst = fake_instance.fake_db_instance()
1291
+        db_inst['system_metadata'] = flavors.save_flavor_info({}, flavor)
1292
+        db_inst['extra'] = None
1293
+        with mock.patch('nova.db.instance_get_by_uuid') as mock_get:
1294
+            mock_get.return_value = db_inst
1295
+            inst = objects.Instance.get_by_uuid(
1296
+                self.context, uuid='foo',
1297
+                expected_attrs=['numa_topology', 'pci_requests', 'vcpu_model',
1298
+                                'flavor'])
1299
+            for field in ('numa_topology', 'pci_requests', 'vcpu_model'):
1300
+                self.assertTrue(inst.obj_attr_is_set(field))
1301
+                self.assertIsNone(getattr(inst, field))
1302
+            self.assertTrue(inst.obj_attr_is_set('flavor'))
1303
+
1272 1304
 
1273 1305
 class TestInstanceObject(test_objects._LocalTest,
1274 1306
                          _TestInstanceObject):

Loading…
Cancel
Save