Fix migrate_flavor_data() to catch instances with no instance_extra rows

The way the query was being performed previously, we would not see any
instances that didn't have a row in instance_extra. This could happen if
an instance hasn't been touched for several releases, or if the data
set is old.

The fix is a simple change to use outerjoin instead of join. This patch
includes a test that ensures that instances with no instance_extra rows
are included in the migration. If we query an instance without such a
row, we create it before doing a save on the instance.

Closes-Bug: #1447132
Change-Id: I2620a8a4338f5c493350f26cdba3e41f3cb28de7
(cherry picked from commit 92714accc4)
This commit is contained in:
Dan Smith 2015-04-22 09:02:03 -07:00
parent a0efbbcfc7
commit a2872a9262
2 changed files with 31 additions and 1 deletions

View File

@ -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

View File

@ -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):