cmd: Remove 'nova-manage db null_instance_uuid_scan'

Change I2aae01ed235f1257b0b3ddc6aee4efc7be38eb6e indicated that this
command was no longer necessary and could be removed. In hindsight, it's
been unnecessary since Liberty, which introduced a blocking migration
requiring this script be run, and it could have been deleted years ago.
No time like the present though.

Change-Id: I532c7918a8e2c887f29d2f0e1e33b80f2b3a7507
Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
This commit is contained in:
Stephen Finucane 2021-02-02 16:54:28 +00:00
parent 726e2fd03b
commit 2d4eff0ef7
7 changed files with 6 additions and 178 deletions

View File

@ -230,9 +230,6 @@ Nova Database
arguments are not provided, 2 if an invalid date is provided, 3 if no
data was deleted, 4 if the list of cells cannot be obtained.
``nova-manage db null_instance_uuid_scan [--delete]``
Lists and optionally deletes database records where instance_uuid is NULL.
``nova-manage db online_data_migrations [--max-count]``
Perform data migration to update all live data.

View File

@ -463,35 +463,6 @@ Error: %s""") % str(e))
else:
return 3
@args('--delete', action='store_true', dest='delete',
help='If specified, automatically delete any records found where '
'instance_uuid is NULL.')
def null_instance_uuid_scan(self, delete=False):
"""Lists and optionally deletes database records where
instance_uuid is NULL.
"""
hits = migration.db_null_instance_uuid_scan(delete)
records_found = False
for table_name, records in hits.items():
# Don't print anything for 0 hits
if records:
records_found = True
if delete:
print(_("Deleted %(records)d records "
"from table '%(table_name)s'.") %
{'records': records, 'table_name': table_name})
else:
print(_("There are %(records)d records in the "
"'%(table_name)s' table where the uuid or "
"instance_uuid column is NULL. Run this "
"command again with the --delete option after you "
"have backed up any necessary data.") %
{'records': records, 'table_name': table_name})
# check to see if we didn't find anything
if not records_found:
print(_('There were no records found where '
'instance_uuid was NULL.'))
def _run_migration(self, ctxt, max_count):
ran = 0
exceptions = False

View File

@ -34,23 +34,3 @@ def db_version(database='main', context=None):
def db_initial_version(database='main'):
"""The starting version for the database."""
return IMPL.db_initial_version(database=database)
def db_null_instance_uuid_scan(delete=False):
"""Utility for scanning the database to look for NULL instance uuid rows.
Scans the backing nova database to look for table entries where
instances.uuid or instance_uuid columns are NULL (except for the
fixed_ips table since that can contain NULL instance_uuid entries by
design). Dumps the tables that have NULL instance_uuid entries or
optionally deletes them based on usage.
This tool is meant to be used in conjunction with the 267 database
migration script to detect and optionally cleanup NULL instance_uuid
records.
:param delete: If true, delete NULL instance_uuid records found, else
just query to see if they exist for reporting.
:returns: dict of table name to number of hits for NULL instance_uuid rows.
"""
return IMPL.db_null_instance_uuid_scan(delete=delete)

View File

@ -19,7 +19,6 @@ import os
from migrate import exceptions as versioning_exceptions
from migrate.versioning import api as versioning_api
from migrate.versioning.repository import Repository
from oslo_db.sqlalchemy import utils as db_utils
from oslo_log import log as logging
import sqlalchemy
from sqlalchemy.sql import null
@ -159,38 +158,6 @@ def _process_null_records(table, col_name, check_fkeys, delete=False):
return records
def db_null_instance_uuid_scan(delete=False):
"""Scans the database for NULL instance_uuid records.
:param delete: If true, delete NULL instance_uuid records found, else
just query to see if they exist for reporting.
:returns: dict of table name to number of hits for NULL instance_uuid rows.
"""
engine = get_engine()
meta = sqlalchemy.MetaData(bind=engine)
# NOTE(mriedem): We're going to load up all of the tables so we can find
# any with an instance_uuid column since those may be foreign keys back
# to the instances table and we want to cleanup those records first. We
# have to do this explicitly because the foreign keys in nova aren't
# defined with cascading deletes.
meta.reflect(engine)
# Keep track of all of the tables that had hits in the query.
processed = {}
for table in reversed(meta.sorted_tables):
# Ignore the fixed_ips table by design.
if table.name not in ('fixed_ips', 'shadow_fixed_ips'):
processed[table.name] = _process_null_records(
table, 'instance_uuid', check_fkeys=True, delete=delete)
# Now process the *instances tables.
for table_name in ('instances', 'shadow_instances'):
table = db_utils.get_table(engine, table_name)
processed[table.name] = _process_null_records(
table, 'uuid', check_fkeys=False, delete=delete)
return processed
def db_version_control(version=None, database='main', context=None):
repository = _find_migrate_repo(database)
versioning_api.version_control(get_engine(database, context=context),

View File

@ -30,7 +30,6 @@ from nova.cmd import manage
from nova import conf
from nova import context
from nova.db import api as db
from nova.db import migration
from nova.db.sqlalchemy import migration as sqla_migration
from nova import exception
from nova import objects
@ -584,32 +583,6 @@ Cell %s: 456
self.assertEqual(4, ret)
self.assertIn('Unable to get cell list', self.output.getvalue())
@mock.patch.object(migration, 'db_null_instance_uuid_scan',
return_value={'foo': 0})
def test_null_instance_uuid_scan_no_records_found(self, mock_scan):
self.commands.null_instance_uuid_scan()
self.assertIn("There were no records found", self.output.getvalue())
@mock.patch.object(migration, 'db_null_instance_uuid_scan',
return_value={'foo': 1, 'bar': 0})
def _test_null_instance_uuid_scan(self, mock_scan, delete):
self.commands.null_instance_uuid_scan(delete)
output = self.output.getvalue()
if delete:
self.assertIn("Deleted 1 records from table 'foo'.", output)
self.assertNotIn("Deleted 0 records from table 'bar'.", output)
else:
self.assertIn("1 records in the 'foo' table", output)
self.assertNotIn("0 records in the 'bar' table", output)
self.assertNotIn("There were no records found", output)
def test_null_instance_uuid_scan_readonly(self):
self._test_null_instance_uuid_scan(delete=False)
def test_null_instance_uuid_scan_delete(self):
self._test_null_instance_uuid_scan(delete=True)
@mock.patch.object(sqla_migration, 'db_version', return_value=2)
def test_version(self, sqla_migrate):
self.commands.version()

View File

@ -15,7 +15,6 @@
import importlib
from migrate import exceptions as versioning_exceptions
from migrate import UniqueConstraint
from migrate.versioning import api as versioning_api
import mock
from oslo_db.sqlalchemy import utils as db_utils
@ -32,71 +31,6 @@ from nova import test
from nova.tests import fixtures as nova_fixtures
class TestNullInstanceUuidScanDB(test.TestCase):
# NOTE(mriedem): Copied from the 267 database migration.
def downgrade(self, migrate_engine):
UniqueConstraint('uuid',
table=db_utils.get_table(migrate_engine, 'instances'),
name='uniq_instances0uuid').drop()
for table_name in ('instances', 'shadow_instances'):
table = db_utils.get_table(migrate_engine, table_name)
table.columns.uuid.alter(nullable=True)
def setUp(self):
super(TestNullInstanceUuidScanDB, self).setUp()
self.engine = db_api.get_engine()
# When this test runs, we've already run the schema migration to make
# instances.uuid non-nullable, so we have to alter the table here
# so we can test against a real database.
self.downgrade(self.engine)
# Now create fake entries in the fixed_ips, consoles and
# instances table where (instance_)uuid is None for testing.
for table_name in ('fixed_ips', 'instances', 'consoles'):
table = db_utils.get_table(self.engine, table_name)
fake_record = {'id': 1}
table.insert().execute(fake_record)
def test_db_null_instance_uuid_scan_readonly(self):
results = migration.db_null_instance_uuid_scan(delete=False)
self.assertEqual(1, results.get('instances'))
self.assertEqual(1, results.get('consoles'))
# The fixed_ips table should be ignored.
self.assertNotIn('fixed_ips', results)
# Now pick a random table with an instance_uuid column and show it's
# in the results but with 0 hits.
self.assertEqual(0, results.get('instance_info_caches'))
# Make sure nothing was deleted.
for table_name in ('fixed_ips', 'instances', 'consoles'):
table = db_utils.get_table(self.engine, table_name)
record = table.select(table.c.id == 1).execute().first()
self.assertIsNotNone(record)
def test_db_null_instance_uuid_scan_delete(self):
results = migration.db_null_instance_uuid_scan(delete=True)
self.assertEqual(1, results.get('instances'))
self.assertEqual(1, results.get('consoles'))
# The fixed_ips table should be ignored.
self.assertNotIn('fixed_ips', results)
# Now pick a random table with an instance_uuid column and show it's
# in the results but with 0 hits.
self.assertEqual(0, results.get('instance_info_caches'))
# Make sure fixed_ips wasn't touched, but instances and instance_faults
# records were deleted.
fixed_ips = db_utils.get_table(self.engine, 'fixed_ips')
record = fixed_ips.select(fixed_ips.c.id == 1).execute().first()
self.assertIsNotNone(record)
consoles = db_utils.get_table(self.engine, 'consoles')
record = consoles.select(consoles.c.id == 1).execute().first()
self.assertIsNone(record)
instances = db_utils.get_table(self.engine, 'instances')
record = instances.select(instances.c.id == 1).execute().first()
self.assertIsNone(record)
@mock.patch.object(migration, 'db_version', return_value=2)
@mock.patch.object(migration, '_find_migrate_repo', return_value='repo')
@mock.patch.object(versioning_api, 'upgrade')

View File

@ -0,0 +1,6 @@
---
upgrade:
- |
The ``nova-manage db null_instance_uuid_scan`` command has been removed.
A blocking migration has been in place since the 12.0.0 (Liberty) release
making this check unnecessary.