From e5152a2ee383a3d92a7a5a0750ee4753ead55e35 Mon Sep 17 00:00:00 2001 From: Dan Smith Date: Mon, 28 Aug 2017 10:56:59 -0700 Subject: [PATCH] Add uuid online migration for migrations This adds an online data migration for nova-manage that will background- process migrations in the database to have a uuid. Related to blueprint migration-allocations Change-Id: I5b4b235b88367c361d38371d430d67ff583a906c --- nova/cmd/manage.py | 3 +++ nova/db/sqlalchemy/api.py | 19 ++++++++++++++++++ nova/tests/unit/db/test_db_api.py | 32 +++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/nova/cmd/manage.py b/nova/cmd/manage.py index 89494bcf3b..b46fa368c0 100644 --- a/nova/cmd/manage.py +++ b/nova/cmd/manage.py @@ -82,6 +82,7 @@ from nova import config from nova import context from nova import db from nova.db import migration +from nova.db.sqlalchemy import api as sa_db from nova import exception from nova.i18n import _ from nova import objects @@ -666,6 +667,8 @@ class DbCommands(object): quotas_obj.migrate_quota_limits_to_api_db, # Added in Pike quotas_obj.migrate_quota_classes_to_api_db, + # Added in Queens + sa_db.migration_migrate_to_uuid, ) def __init__(self): diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index afe1b80e40..4e69506c58 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -4821,6 +4821,25 @@ def migration_get_all_by_filters(context, filters): return query.all() +@pick_context_manager_writer +def migration_migrate_to_uuid(context, count): + # Avoid circular import + from nova import objects + + db_migrations = model_query(context, models.Migration).filter_by( + uuid=None).limit(count).all() + + done = 0 + for db_migration in db_migrations: + mig = objects.Migration(context) + mig._from_db_object(context, mig, db_migration) + done += 1 + + # We don't have any situation where we can (detectably) not + # migrate a thing, so report anything that matched as "completed". + return done, done + + ################## diff --git a/nova/tests/unit/db/test_db_api.py b/nova/tests/unit/db/test_db_api.py index 75e3d1d183..7f33029a56 100644 --- a/nova/tests/unit/db/test_db_api.py +++ b/nova/tests/unit/db/test_db_api.py @@ -3827,6 +3827,38 @@ class ServiceTestCase(test.TestCase, ModelsObjectComparatorMixin): self.assertEqual(0, total) self.assertEqual(0, done) + def test_migration_migrate_to_uuid(self): + total, done = sqlalchemy_api.migration_migrate_to_uuid(self.ctxt, 10) + self.assertEqual(0, total) + self.assertEqual(0, done) + + # Create two migrations, one with a uuid and one without. + db.migration_create(self.ctxt, + dict(source_compute='src', source_node='srcnode', + dest_compute='dst', dest_node='dstnode', + status='running')) + db.migration_create(self.ctxt, + dict(source_compute='src', source_node='srcnode', + dest_compute='dst', dest_node='dstnode', + status='running', + uuid=uuidsentinel.migration2)) + + # Now migrate them, we should find one and update one + total, done = sqlalchemy_api.migration_migrate_to_uuid(self.ctxt, 10) + self.assertEqual(1, total) + self.assertEqual(1, done) + + # Get the migrations back to make sure the original uuid didn't change. + migrations = db.migration_get_all_by_filters(self.ctxt, {}) + uuids = [m.uuid for m in migrations] + self.assertIn(uuidsentinel.migration2, uuids) + self.assertNotIn(None, uuids) + + # Run the online migration again to see nothing was processed. + total, done = sqlalchemy_api.migration_migrate_to_uuid(self.ctxt, 10) + self.assertEqual(0, total) + self.assertEqual(0, done) + class BaseInstanceTypeTestCase(test.TestCase, ModelsObjectComparatorMixin): def setUp(self):