]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
[neutron-db-manage] Introduce contract and expand commands
authorIhar Hrachyshka <ihrachys@redhat.com>
Mon, 24 Aug 2015 15:58:12 +0000 (17:58 +0200)
committerIhar Hrachyshka <ihrachys@redhat.com>
Thu, 27 Aug 2015 11:43:04 +0000 (13:43 +0200)
Those are just wrappers that pass proper @head revision into upgrade
alembic API.

Change-Id: I4d7e1bd992c3ad75fca6d72defa9f96565ad6ba9
Partially-Implements: blueprint online-schema-migrations

doc/source/devref/alembic_migrations.rst
neutron/db/migration/cli.py
neutron/tests/unit/db/test_migration.py

index 725bc46f6488f410813d53bf9d4ae448044b12ab..61cbba47fee09c9a112b8f3181f17274fed75462 100644 (file)
@@ -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.
 
index d33baa84df72a49f1dafdb2a1fb915f19575c828..2d8c63780851df23420a4d4b8846a2277be2b7e2 100644 (file)
@@ -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)")
index 3de29cb7bbc8afeb372985a485bf2d0dc6655b2a..4612f0e46a4ef3a767a2ff7f987a580edda395c2 100644 (file)
@@ -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):