diff options
author | Dan Smith <dansmith@redhat.com> | 2015-04-22 09:02:03 -0700 |
---|---|---|
committer | Dan Smith <dansmith@redhat.com> | 2015-04-23 06:53:21 -0700 |
commit | a2872a9262985bd0ee2c6df4f7593947e0516406 (patch) | |
tree | 9ad1c96d3900f2eab1126b2709e1a73bb2179fd1 | |
parent | a0efbbcfc701563473e0dc42ca5b6b4b57ca7d5a (diff) | |
download | nova-a2872a9262985bd0ee2c6df4f7593947e0516406.tar.gz |
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 92714accc49e85579f406de10ef8b3b510277037)
-rw-r--r-- | nova/db/sqlalchemy/api.py | 7 | ||||
-rw-r--r-- | nova/tests/unit/db/test_db_api.py | 25 |
2 files changed, 31 insertions, 1 deletions
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index fc35a5faee..64c6724e64 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 8fc8d540fe..7cc9c94a52 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): |