diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index fc35a5faee12..64c6724e647d 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -6041,7 +6041,7 @@ def migrate_flavor_data(context, max_count, flavor_cache): from nova import objects query = _instance_get_all_query(context, joins=['extra', 'extra.flavor']).\ - join(models.Instance.extra).\ + outerjoin(models.Instance.extra).\ filter(models.InstanceExtra.flavor.is_(None)) if max_count is not None: instances = query.limit(max_count) @@ -6069,6 +6069,11 @@ def migrate_flavor_data(context, max_count, flavor_cache): _augment_flavors_to_migrate(instance, flavor_cache) if instance.obj_what_changed(): + if db_instance.get('extra') is None: + _instance_extra_create(context, + {'instance_uuid': db_instance['uuid']}) + LOG.debug( + 'Created instance_extra for %s' % db_instance['uuid']) instance.save(expected_task_state=[None]) count_hit += 1 diff --git a/nova/tests/unit/db/test_db_api.py b/nova/tests/unit/db/test_db_api.py index 8fc8d540fe46..7cc9c94a52c1 100644 --- a/nova/tests/unit/db/test_db_api.py +++ b/nova/tests/unit/db/test_db_api.py @@ -7629,6 +7629,31 @@ class FlavorMigrationTestCase(test.TestCase): self.assertEqual(3, match) self.assertEqual(0, done) + def test_migrate_flavor_gets_missing_extra_rows(self): + ctxt = context.get_admin_context() + flavor = flavors.get_default_flavor() + sysmeta = flavors.save_flavor_info({}, flavor) + values1 = {'uuid': str(stdlib_uuid.uuid4()), + 'system_metadata': sysmeta, + 'extra': {'flavor': None}, + } + db.instance_create(ctxt, values1) + values2 = {'uuid': str(stdlib_uuid.uuid4()), + 'system_metadata': sysmeta, + } + inst2 = db.instance_create(ctxt, values2) + sqlalchemy_api.model_query(ctxt, models.InstanceExtra).\ + filter_by(instance_uuid=inst2.uuid).delete() + + self.assertIsNone(db.instance_extra_get_by_instance_uuid( + ctxt, inst2.uuid)) + match, done = db.migrate_flavor_data(ctxt, None, {}) + self.assertEqual(2, match) + self.assertEqual(2, done) + extra = db.instance_extra_get_by_instance_uuid(ctxt, inst2.uuid) + self.assertIsNotNone(extra) + self.assertIsNotNone(extra.flavor) + class ArchiveTestCase(test.TestCase):