diff --git a/doc/source/cli/nova-manage.rst b/doc/source/cli/nova-manage.rst index aa699b1eee..ab33e7c4b6 100644 --- a/doc/source/cli/nova-manage.rst +++ b/doc/source/cli/nova-manage.rst @@ -60,7 +60,7 @@ Nova Database determined by ``[database]/connection`` in the configuration file passed to nova-manage. -``nova-manage db archive_deleted_rows [--max_rows ] [--verbose] [--until-complete]`` +``nova-manage db archive_deleted_rows [--max_rows ] [--verbose] [--until-complete] [--purge]`` Move deleted rows from production tables to shadow tables. Note that the corresponding rows in the instance_mappings and request_specs tables of the @@ -68,7 +68,10 @@ Nova Database --verbose will print the results of the archive operation for any tables that were changed. Specifying --until-complete will make the command run continuously until all deleted rows are archived. Use the --max_rows option, - which defaults to 1000, as a batch size for each iteration. + which defaults to 1000, as a batch size for each iteration. Specifying --purge + will cause a `full` DB purge to be completed after archival. If a date range + is desired for the purge, then run ``nova-manage db purge --before + `` manually after archiving is complete. ``nova-manage db purge [--all] [--before ] [--verbose]`` diff --git a/nova/cmd/manage.py b/nova/cmd/manage.py index a089582bf6..656dfa8d85 100644 --- a/nova/cmd/manage.py +++ b/nova/cmd/manage.py @@ -488,8 +488,10 @@ Error: %s""") % six.text_type(e)) default=False, help=('Run continuously until all deleted rows are archived. Use ' 'max_rows as a batch size for each iteration.')) + @args('--purge', action='store_true', dest='purge', default=False, + help='Purge all data from shadow tables after archive completes') def archive_deleted_rows(self, max_rows=1000, verbose=False, - until_complete=False): + until_complete=False, purge=False): """Move deleted rows from production tables to shadow tables. Returns 0 if nothing was archived, 1 if some number of rows were @@ -544,6 +546,12 @@ Error: %s""") % six.text_type(e)) dict_value=_('Number of Rows Archived')) else: print(_('Nothing was archived.')) + + if table_to_rows_archived and purge: + if verbose: + print(_('Rows were archived, running purge...')) + self.purge(purge_all=True, verbose=verbose) + # NOTE(danms): Return nonzero if we archived something return int(bool(table_to_rows_archived)) diff --git a/nova/tests/unit/test_nova_manage.py b/nova/tests/unit/test_nova_manage.py index 34942b1ccd..24fe11676d 100644 --- a/nova/tests/unit/test_nova_manage.py +++ b/nova/tests/unit/test_nova_manage.py @@ -447,15 +447,18 @@ Archiving.....complete def test_archive_deleted_rows_until_complete_quiet(self): self.test_archive_deleted_rows_until_complete(verbose=False) + @mock.patch('nova.db.sqlalchemy.api.purge_shadow_tables') @mock.patch.object(db, 'archive_deleted_rows') def test_archive_deleted_rows_until_stopped(self, mock_db_archive, + mock_db_purge, verbose=True): mock_db_archive.side_effect = [ ({'instances': 10, 'instance_extra': 5}, list()), ({'instances': 5, 'instance_faults': 1}, list()), KeyboardInterrupt] result = self.commands.archive_deleted_rows(20, verbose=verbose, - until_complete=True) + until_complete=True, + purge=True) self.assertEqual(1, result) if verbose: expected = """\ @@ -467,6 +470,7 @@ Archiving.....stopped | instance_faults | 1 | | instances | 15 | +-----------------+-------------------------+ +Rows were archived, running purge... """ else: expected = '' @@ -475,15 +479,18 @@ Archiving.....stopped mock_db_archive.assert_has_calls([mock.call(20), mock.call(20), mock.call(20)]) + mock_db_purge.assert_called_once_with(None, status_fn=mock.ANY) def test_archive_deleted_rows_until_stopped_quiet(self): self.test_archive_deleted_rows_until_stopped(verbose=False) @mock.patch.object(db, 'archive_deleted_rows', return_value=({}, [])) def test_archive_deleted_rows_verbose_no_results(self, mock_db_archive): - result = self.commands.archive_deleted_rows(20, verbose=True) + result = self.commands.archive_deleted_rows(20, verbose=True, + purge=True) mock_db_archive.assert_called_once_with(20) output = self.output.getvalue() + # If nothing was archived, there should be no purge messages self.assertIn('Nothing was archived.', output) self.assertEqual(0, result) diff --git a/releasenotes/notes/purge-db-command-d4cd9ea5400f479c.yaml b/releasenotes/notes/purge-db-command-d4cd9ea5400f479c.yaml index 8f53be1b44..7c4c716126 100644 --- a/releasenotes/notes/purge-db-command-d4cd9ea5400f479c.yaml +++ b/releasenotes/notes/purge-db-command-d4cd9ea5400f479c.yaml @@ -2,4 +2,6 @@ features: - | The nova-manage command now has a 'db purge' command that will delete data - from the shadow tables after 'db archive_deleted_rows' has been run. + from the shadow tables after 'db archive_deleted_rows' has been run. There + is also now a ``--purge`` option for 'db archive_deleted_rows' that will + automatically do a full purge after archiving.