From f3bb778dcb213d81aa62e504afb10b3bac614bb4 Mon Sep 17 00:00:00 2001 From: Henry Gessau Date: Sun, 27 Sep 2015 15:36:59 -0400 Subject: [PATCH] Tag the alembic migration revisions for Liberty Previously when we had one repo with one alembic branch we would create a milestone revision on that single branch. Now we have multiple repos and expand/contract branches for each repo. So from now on we tag the final revision on every branch when we make a milestone release. Update the cli to support the command: neutron-db-manage upgrade where becomes an alias for all the revisions for a milestone. Closes-Bug: #1499033 Change-Id: I38623986dd574bec01fe147f9c6a747f3f512bb7 (cherry picked from commit 52236764a3a7c23ec24a86ccb84bc6737e2a4791) Conflicts: neutron/db/migration/cli.py neutron/tests/unit/db/test_migration.py --- neutron/db/migration/__init__.py | 7 ++++ ...f11ca47297_drop_cisco_monolithic_tables.py | 8 +++- .../34af2b5c5a59_add_dns_name_to_port.py | 13 ++++-- neutron/db/migration/cli.py | 35 ++++++++++++---- neutron/tests/unit/db/test_migration.py | 42 +++++++++++++++++++ 5 files changed, 92 insertions(+), 13 deletions(-) diff --git a/neutron/db/migration/__init__.py b/neutron/db/migration/__init__.py index 5561e884d..81b491083 100644 --- a/neutron/db/migration/__init__.py +++ b/neutron/db/migration/__init__.py @@ -21,6 +21,13 @@ from alembic import op import sqlalchemy as sa from sqlalchemy.engine import reflection +# Neutron milestones for upgrade aliases +LIBERTY = 'liberty' + +NEUTRON_MILESTONES = [ + # earlier milestones were not tagged + LIBERTY, +] CREATION_OPERATIONS = (sa.sql.ddl.CreateIndex, sa.sql.ddl.CreateTable, diff --git a/neutron/db/migration/alembic_migrations/versions/liberty/contract/4af11ca47297_drop_cisco_monolithic_tables.py b/neutron/db/migration/alembic_migrations/versions/liberty/contract/4af11ca47297_drop_cisco_monolithic_tables.py index ee39fa952..7a91b79b3 100644 --- a/neutron/db/migration/alembic_migrations/versions/liberty/contract/4af11ca47297_drop_cisco_monolithic_tables.py +++ b/neutron/db/migration/alembic_migrations/versions/liberty/contract/4af11ca47297_drop_cisco_monolithic_tables.py @@ -21,11 +21,17 @@ Create Date: 2015-08-13 08:01:19.709839 """ +from alembic import op + +from neutron.db import migration + + # revision identifiers, used by Alembic. revision = '4af11ca47297' down_revision = '11926bcfe72d' -from alembic import op +# milestone identifier, used by neutron-db-manage +neutron_milestone = [migration.LIBERTY] def upgrade(): diff --git a/neutron/db/migration/alembic_migrations/versions/liberty/expand/34af2b5c5a59_add_dns_name_to_port.py b/neutron/db/migration/alembic_migrations/versions/liberty/expand/34af2b5c5a59_add_dns_name_to_port.py index ba523ae65..3b2707c74 100644 --- a/neutron/db/migration/alembic_migrations/versions/liberty/expand/34af2b5c5a59_add_dns_name_to_port.py +++ b/neutron/db/migration/alembic_migrations/versions/liberty/expand/34af2b5c5a59_add_dns_name_to_port.py @@ -21,16 +21,21 @@ Create Date: 2015-08-23 00:22:47.618593 """ -# revision identifiers, used by Alembic. -revision = '34af2b5c5a59' -down_revision = '9859ac9c136' - from alembic import op import sqlalchemy as sa +from neutron.db import migration from neutron.extensions import dns +# revision identifiers, used by Alembic. +revision = '34af2b5c5a59' +down_revision = '9859ac9c136' + +# milestone identifier, used by neutron-db-manage +neutron_milestone = [migration.LIBERTY] + + def upgrade(): op.add_column('ports', sa.Column('dns_name', diff --git a/neutron/db/migration/cli.py b/neutron/db/migration/cli.py index 4c7ea5b1b..4c4169a0c 100644 --- a/neutron/db/migration/cli.py +++ b/neutron/db/migration/cli.py @@ -25,12 +25,13 @@ from oslo_utils import importutils import pkg_resources from neutron.common import utils +from neutron.db import migration # TODO(ihrachyshka): maintain separate HEAD files per branch HEAD_FILENAME = 'HEAD' HEADS_FILENAME = 'HEADS' -CURRENT_RELEASE = "liberty" +CURRENT_RELEASE = migration.LIBERTY EXPAND_BRANCH = 'expand' CONTRACT_BRANCH = 'contract' @@ -126,8 +127,20 @@ def add_alembic_subparser(sub, cmd): return sub.add_parser(cmd, help=getattr(alembic_command, cmd).__doc__) +def _find_milestone_revisions(config, milestone, branch=None): + """Return the revision(s) for a given milestone.""" + script = alembic_script.ScriptDirectory.from_config(config) + return [ + (m.revision, label) + for m in script.walk_revisions(base='base', head='heads') + for label in (m.branch_labels or [None]) + if milestone in getattr(m.module, 'neutron_milestone', []) and + (branch is None or branch in m.branch_labels) + ] + + def do_upgrade(config, cmd): - desc = None + branch = None if ((CONF.command.revision or CONF.command.delta) and (CONF.command.expand or CONF.command.contract)): @@ -135,11 +148,11 @@ def do_upgrade(config, cmd): 'Phase upgrade options do not accept revision specification')) if CONF.command.expand: - desc = EXPAND_BRANCH + branch = EXPAND_BRANCH revision = _get_branch_head(EXPAND_BRANCH) elif CONF.command.contract: - desc = CONTRACT_BRANCH + branch = CONTRACT_BRANCH revision = _get_branch_head(CONTRACT_BRANCH) elif not CONF.command.revision and not CONF.command.delta: @@ -165,10 +178,16 @@ def do_upgrade(config, cmd): if revision == 'head': revision = 'heads' - if not CONF.command.sql: - run_sanity_checks(config, revision) - do_alembic_command(config, cmd, revision=revision, - desc=desc, sql=CONF.command.sql) + if revision in migration.NEUTRON_MILESTONES: + revisions = _find_milestone_revisions(config, revision, branch) + else: + revisions = [(revision, branch)] + + for revision, branch in revisions: + if not CONF.command.sql: + run_sanity_checks(config, revision) + do_alembic_command(config, cmd, revision=revision, + desc=branch, sql=CONF.command.sql) def no_downgrade(config, cmd): diff --git a/neutron/tests/unit/db/test_migration.py b/neutron/tests/unit/db/test_migration.py index 399fc5070..a88a6e93c 100644 --- a/neutron/tests/unit/db/test_migration.py +++ b/neutron/tests/unit/db/test_migration.py @@ -26,6 +26,7 @@ import mock import pkg_resources import sqlalchemy as sa +from neutron.common import utils from neutron.db import migration from neutron.db.migration import autogen from neutron.db.migration import cli @@ -45,6 +46,8 @@ class FakeRevision(object): labels = set() self.branch_labels = labels self.down_revision = down_revision + self.revision = utils.get_random_string(10) + self.module = mock.MagicMock() class MigrationEntrypointsMemento(fixtures.Fixture): @@ -601,6 +604,45 @@ class TestCli(base.BaseTestCase): alembic_ag_api.render_python_code(contract.upgrade_ops) ) + @mock.patch('alembic.script.ScriptDirectory.walk_revisions') + def test__find_milestone_revisions_one_branch(self, walk_mock): + c_revs = [FakeRevision(labels={cli.CONTRACT_BRANCH}) for r in range(5)] + c_revs[1].module.neutron_milestone = [migration.LIBERTY] + + walk_mock.return_value = c_revs + m = cli._find_milestone_revisions(self.configs[0], 'liberty', + cli.CONTRACT_BRANCH) + self.assertEqual(1, len(m)) + m = cli._find_milestone_revisions(self.configs[0], 'liberty', + cli.EXPAND_BRANCH) + self.assertEqual(0, len(m)) + + @mock.patch('alembic.script.ScriptDirectory.walk_revisions') + def test__find_milestone_revisions_two_branches(self, walk_mock): + c_revs = [FakeRevision(labels={cli.CONTRACT_BRANCH}) for r in range(5)] + c_revs[1].module.neutron_milestone = [migration.LIBERTY] + e_revs = [FakeRevision(labels={cli.EXPAND_BRANCH}) for r in range(5)] + e_revs[3].module.neutron_milestone = [migration.LIBERTY] + + walk_mock.return_value = c_revs + e_revs + m = cli._find_milestone_revisions(self.configs[0], 'liberty') + self.assertEqual(2, len(m)) + + m = cli._find_milestone_revisions(self.configs[0], 'mitaka') + self.assertEqual(0, len(m)) + + @mock.patch('alembic.script.ScriptDirectory.walk_revisions') + def test__find_milestone_revisions_branchless(self, walk_mock): + revisions = [FakeRevision() for r in range(5)] + revisions[2].module.neutron_milestone = [migration.LIBERTY] + + walk_mock.return_value = revisions + m = cli._find_milestone_revisions(self.configs[0], 'liberty') + self.assertEqual(1, len(m)) + + m = cli._find_milestone_revisions(self.configs[0], 'mitaka') + self.assertEqual(0, len(m)) + class TestSafetyChecks(base.BaseTestCase): -- 2.45.2