Make cinder-manage online migrations more verbose

This makes the online_data_migrations command for cinder-manage a little
more verbose in what it is doing. Each time it is run, it will show you
all the migrations that need running and how many records remain for
each. Basically, you run this until you see all zeroes.

Sample output of $cinder-manage db online_data_migrations

+------------+-------+------+-----------+
| Migration  | Found | Done | Remaining |
+------------+-------+------+-----------+
| mock_mig_1 |   5   |  4   |     1     |
| mock_mig_2 |   6   |  6   |     0     |
+------------+-------+------+-----------+

Change-Id: I572bf2eb560698766d741bd2fd78c8b1067335d0
This commit is contained in:
Karthik Prabhu Vinod 2017-02-28 00:36:44 +00:00
parent 669fd027bf
commit 939fa2c0ff
3 changed files with 75 additions and 9 deletions

View File

@ -57,6 +57,7 @@ from __future__ import print_function
import logging as python_logging
import os
import prettytable
import sys
import time
@ -67,9 +68,6 @@ from oslo_log import log as logging
import oslo_messaging as messaging
from oslo_utils import timeutils
from cinder import i18n
i18n.enable_lazy()
# Need to register global_opts
from cinder.common import config # noqa
from cinder.common import constants
@ -246,6 +244,7 @@ class DbCommands(object):
def _run_migration(self, ctxt, max_count, ignore_state):
ran = 0
migrations = {}
for migration_meth in self.online_migrations:
count = max_count - ran
try:
@ -255,16 +254,24 @@ class DbCommands(object):
{'method': migration_meth.__name__})
found = done = 0
name = migration_meth.__name__
remaining = found - done
if found:
print(_('%(total)i rows matched query %(meth)s, %(done)i '
'migrated') % {'total': found,
'meth': migration_meth.__name__,
'done': done})
print(_('%(found)i rows matched query %(meth)s, %(done)i '
'migrated, %(remaining)i remaining') % {'found': found,
'meth': name,
'done': done,
'remaining':
remaining})
migrations.setdefault(name, (0, 0, 0))
migrations[name] = (migrations[name][0] + found,
migrations[name][1] + done,
migrations[name][2] + remaining)
if max_count is not None:
ran += done
if ran >= max_count:
break
return ran
return migrations
@args('--max_count', metavar='<number>', dest='max_count', type=int,
help='Maximum number of objects to consider.')
@ -286,11 +293,23 @@ class DbCommands(object):
print(_('Running batches of %i until complete.') % max_count)
ran = None
migration_info = {}
while ran is None or ran != 0:
ran = self._run_migration(ctxt, max_count, ignore_state)
migrations = self._run_migration(ctxt, max_count, ignore_state)
migration_info.update(migrations)
ran = sum([done for found, done, remaining in migrations.values()])
if not unlimited:
break
t = prettytable.PrettyTable([_('Migration'),
_('Found'),
_('Done'),
_('Remaining')])
for name in sorted(migration_info.keys()):
info = migration_info[name]
t.add_row([name, info[0], info[1], info[2]])
print(t)
sys.exit(1 if ran else 0)

View File

@ -16,10 +16,12 @@ import sys
import time
import ddt
import fixtures
import mock
from oslo_config import cfg
from oslo_utils import timeutils
import six
from six.moves import StringIO
try:
import rtslib_fb
@ -224,6 +226,45 @@ class TestCinderManageCmd(test.TestCase):
cinder_manage.DbCommands.online_migrations[0].assert_has_calls(
(mock.call(mock.ANY, 50, False),) * 2)
def _fake_db_command(self, migrations=None):
if migrations is None:
mock_mig_1 = mock.MagicMock(__name__="mock_mig_1")
mock_mig_2 = mock.MagicMock(__name__="mock_mig_2")
mock_mig_1.return_value = (5, 4)
mock_mig_2.return_value = (6, 6)
migrations = (mock_mig_1, mock_mig_2)
class _CommandSub(cinder_manage.DbCommands):
online_migrations = migrations
return _CommandSub
@mock.patch('cinder.context.get_admin_context')
def test_online_migrations(self, mock_get_context):
self.useFixture(fixtures.MonkeyPatch('sys.stdout', StringIO()))
ctxt = mock_get_context.return_value
db_cmds = self._fake_db_command()
command = db_cmds()
exit = self.assertRaises(SystemExit,
command.online_data_migrations, 10)
self.assertEqual(1, exit.code)
expected = """\
5 rows matched query mock_mig_1, 4 migrated, 1 remaining
6 rows matched query mock_mig_2, 6 migrated, 0 remaining
+------------+-------+------+-----------+
| Migration | Found | Done | Remaining |
+------------+-------+------+-----------+
| mock_mig_1 | 5 | 4 | 1 |
| mock_mig_2 | 6 | 6 | 0 |
+------------+-------+------+-----------+
"""
command.online_migrations[0].assert_has_calls([mock.call(ctxt,
10, False)])
command.online_migrations[1].assert_has_calls([mock.call(ctxt,
6, False)])
self.assertEqual(expected, sys.stdout.getvalue())
@mock.patch('cinder.cmd.manage.DbCommands.online_migrations',
(mock.Mock(side_effect=((2, 2), (0, 0)), __name__='foo'),))
def test_db_commands_online_data_migrations_ignore_state_and_max(self):

View File

@ -0,0 +1,6 @@
---
features:
- The cinder-manage online_data_migrations command now prints a
tabular summary of completed and remaining records. The goal
here is to get all your numbers to zero. The previous execution
return code behavior is retained for scripting.