From: Ihar Hrachyshka Date: Mon, 24 Aug 2015 15:58:12 +0000 (+0200) Subject: [neutron-db-manage] Introduce contract and expand commands X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=bac73541f420d1802cdf48f4d35b3a6ad1f5b7ee;p=openstack-build%2Fneutron-build.git [neutron-db-manage] Introduce contract and expand commands Those are just wrappers that pass proper @head revision into upgrade alembic API. Change-Id: I4d7e1bd992c3ad75fca6d72defa9f96565ad6ba9 Partially-Implements: blueprint online-schema-migrations --- diff --git a/doc/source/devref/alembic_migrations.rst b/doc/source/devref/alembic_migrations.rst index 725bc46f6..61cbba47f 100644 --- a/doc/source/devref/alembic_migrations.rst +++ b/doc/source/devref/alembic_migrations.rst @@ -294,12 +294,12 @@ Applying database migration rules To apply just expansion rules, execute:: - neutron-db-manage upgrade expand@head + neutron-db-manage upgrade --expand After the first step is done, you can stop neutron-server, apply remaining non-expansive migration rules, if any:: - neutron-db-manage upgrade contract@head + neutron-db-manage upgrade --contract and finally, start your neutron-server again. diff --git a/neutron/db/migration/cli.py b/neutron/db/migration/cli.py index d33baa84d..2d8c63780 100644 --- a/neutron/db/migration/cli.py +++ b/neutron/db/migration/cli.py @@ -98,10 +98,18 @@ CONF.register_cli_opts(_db_opts, 'database') CONF.register_opts(_quota_opts, 'QUOTAS') -def do_alembic_command(config, cmd, *args, **kwargs): +def do_alembic_command(config, cmd, revision=None, desc=None, **kwargs): + args = [] + if revision: + args.append(revision) + project = config.get_main_option('neutron_project') - alembic_util.msg(_('Running %(cmd)s for %(project)s ...') % - {'cmd': cmd, 'project': project}) + if desc: + alembic_util.msg(_('Running %(cmd)s (%(desc)s) for %(project)s ...') % + {'cmd': cmd, 'desc': desc, 'project': project}) + else: + alembic_util.msg(_('Running %(cmd)s for %(project)s ...') % + {'cmd': cmd, 'project': project}) try: getattr(alembic_command, cmd)(config, *args, **kwargs) except alembic_util.CommandError as e: @@ -126,30 +134,48 @@ def add_alembic_subparser(sub, cmd): def do_upgrade(config, cmd): - if not CONF.command.revision and not CONF.command.delta: + desc = None + + if ((CONF.command.revision or CONF.command.delta) and + (CONF.command.expand or CONF.command.contract)): + raise SystemExit(_( + 'Phase upgrade options do not accept revision specification')) + + if CONF.command.expand: + desc = EXPAND_BRANCH + revision = _get_branch_head(EXPAND_BRANCH) + + elif CONF.command.contract: + desc = CONTRACT_BRANCH + revision = _get_branch_head(CONTRACT_BRANCH) + + elif not CONF.command.revision and not CONF.command.delta: raise SystemExit(_('You must provide a revision or relative delta')) - revision = CONF.command.revision or '' - if '-' in revision: - raise SystemExit(_('Negative relative revision (downgrade) not ' - 'supported')) - - delta = CONF.command.delta - if delta: - if '+' in revision: - raise SystemExit(_('Use either --delta or relative revision, ' - 'not both')) - if delta < 0: - raise SystemExit(_('Negative delta (downgrade) not supported')) - revision = '%s+%d' % (revision, delta) - - # leave branchless 'head' revision request backward compatible by applying - # all heads in all available branches. - if revision == 'head': - revision = 'heads' + else: + revision = CONF.command.revision or '' + if '-' in revision: + raise SystemExit(_('Negative relative revision (downgrade) not ' + 'supported')) + + delta = CONF.command.delta + if delta: + if '+' in revision: + raise SystemExit(_('Use either --delta or relative revision, ' + 'not both')) + if delta < 0: + raise SystemExit(_('Negative delta (downgrade) not supported')) + revision = '%s+%d' % (revision, delta) + + # leave branchless 'head' revision request backward compatible by + # applying all heads in all available branches. + if revision == 'head': + revision = 'heads' + if not CONF.command.sql: run_sanity_checks(config, revision) - do_alembic_command(config, cmd, revision, sql=CONF.command.sql) + do_alembic_command(config, cmd, revision=revision, + desc=desc, sql=CONF.command.sql) def no_downgrade(config, cmd): @@ -158,7 +184,7 @@ def no_downgrade(config, cmd): def do_stamp(config, cmd): do_alembic_command(config, cmd, - CONF.command.revision, + revision=CONF.command.revision, sql=CONF.command.sql) @@ -311,6 +337,11 @@ def add_command_parsers(subparsers): default='', help='Change MySQL storage engine of current ' 'existing tables') + + group = parser.add_mutually_exclusive_group() + group.add_argument('--expand', action='store_true') + group.add_argument('--contract', action='store_true') + parser.set_defaults(func=do_upgrade) parser = subparsers.add_parser('downgrade', help="(No longer supported)") diff --git a/neutron/tests/unit/db/test_migration.py b/neutron/tests/unit/db/test_migration.py index 3de29cb7b..4612f0e46 100644 --- a/neutron/tests/unit/db/test_migration.py +++ b/neutron/tests/unit/db/test_migration.py @@ -25,6 +25,7 @@ import pkg_resources from neutron.db import migration from neutron.db.migration import cli from neutron.tests import base +from neutron.tests.unit import testlib_api class FakeConfig(object): @@ -135,14 +136,14 @@ class TestCli(base.BaseTestCase): attrs=attrs) cli.migration_entrypoints[project] = entrypoint - def _main_test_helper(self, argv, func_name, exp_args=(), exp_kwargs=[{}]): + def _main_test_helper(self, argv, func_name, exp_kwargs=[{}]): with mock.patch.object(sys, 'argv', argv),\ mock.patch.object(cli, 'run_sanity_checks'),\ mock.patch.object(cli, 'validate_labels'): cli.main() self.do_alembic_cmd.assert_has_calls( - [mock.call(mock.ANY, func_name, *exp_args, **kwargs) + [mock.call(mock.ANY, func_name, **kwargs) for kwargs in exp_kwargs] ) @@ -150,15 +151,13 @@ class TestCli(base.BaseTestCase): self._main_test_helper( ['prog', 'stamp', 'foo'], 'stamp', - ('foo',), - [{'sql': False}] + [{'revision': 'foo', 'sql': False}] ) self._main_test_helper( ['prog', 'stamp', 'foo', '--sql'], 'stamp', - ('foo',), - [{'sql': True}] + [{'revision': 'foo', 'sql': True}] ) def test_current(self): @@ -192,7 +191,7 @@ class TestCli(base.BaseTestCase): self._main_test_helper( ['prog', 'revision', '--autogenerate', '-m', 'message'], 'revision', - (), expected_kwargs + expected_kwargs ) self.assertEqual(len(self.projects), update.call_count) update.reset_mock() @@ -204,7 +203,7 @@ class TestCli(base.BaseTestCase): self._main_test_helper( ['prog', 'revision', '--sql', '-m', 'message'], 'revision', - (), expected_kwargs + expected_kwargs ) self.assertEqual(len(self.projects), update.call_count) @@ -215,26 +214,70 @@ class TestCli(base.BaseTestCase): # Test that old branchless approach is still supported self._test_database_sync_revision(separate_branches=False) - def test_upgrade(self): + def test_upgrade_revision(self): self._main_test_helper( ['prog', 'upgrade', '--sql', 'head'], 'upgrade', - ('heads',), - [{'sql': True}] + [{'desc': None, 'revision': 'heads', 'sql': True}] ) + def test_upgrade_delta(self): self._main_test_helper( ['prog', 'upgrade', '--delta', '3'], 'upgrade', - ('+3',), - [{'sql': False}] + [{'desc': None, 'revision': '+3', 'sql': False}] ) + def test_upgrade_revision_delta(self): self._main_test_helper( ['prog', 'upgrade', 'kilo', '--delta', '3'], 'upgrade', - ('kilo+3',), - [{'sql': False}] + [{'desc': None, 'revision': 'kilo+3', 'sql': False}] + ) + + def test_upgrade_expand(self): + self._main_test_helper( + ['prog', 'upgrade', '--expand'], + 'upgrade', + [{'desc': cli.EXPAND_BRANCH, + 'revision': 'expand@head', + 'sql': False}] + ) + + def test_upgrade_expand_contract_are_mutually_exclusive(self): + with testlib_api.ExpectedException(SystemExit): + self._main_test_helper( + ['prog', 'upgrade', '--expand --contract'], 'upgrade') + + def _test_upgrade_conflicts_with_revision(self, mode): + with testlib_api.ExpectedException(SystemExit): + self._main_test_helper( + ['prog', 'upgrade', '--%s revision1' % mode], 'upgrade') + + def _test_upgrade_conflicts_with_delta(self, mode): + with testlib_api.ExpectedException(SystemExit): + self._main_test_helper( + ['prog', 'upgrade', '--%s +3' % mode], 'upgrade') + + def test_upgrade_expand_conflicts_with_revision(self): + self._test_upgrade_conflicts_with_revision('expand') + + def test_upgrade_contract_conflicts_with_revision(self): + self._test_upgrade_conflicts_with_revision('contract') + + def test_upgrade_expand_conflicts_with_delta(self): + self._test_upgrade_conflicts_with_delta('expand') + + def test_upgrade_contract_conflicts_with_delta(self): + self._test_upgrade_conflicts_with_delta('contract') + + def test_upgrade_contract(self): + self._main_test_helper( + ['prog', 'upgrade', '--contract'], + 'upgrade', + [{'desc': cli.CONTRACT_BRANCH, + 'revision': 'contract@head', + 'sql': False}] ) def assert_command_fails(self, command):