diff --git a/doc/source/cli/placement-manage.rst b/doc/source/cli/placement-manage.rst index b3c104f65..e45f88cc0 100644 --- a/doc/source/cli/placement-manage.rst +++ b/doc/source/cli/placement-manage.rst @@ -65,3 +65,8 @@ Placement Database connection is determined by ``[placement_database]/connection`` in the configuration file used by placement-manage. If the ``connection`` option is not set, the command will fail. The defined database must already exist. + +``placement-manage db stamp `` + Stamp the revision table with the given revision; don’t run any migrations. + This can be used when the database already exists and you want to bring it + under alembic control. diff --git a/placement/cmd/manage.py b/placement/cmd/manage.py index d33f3c08a..f2eda60a5 100644 --- a/placement/cmd/manage.py +++ b/placement/cmd/manage.py @@ -10,6 +10,7 @@ # License for the specific language governing permissions and limitations # under the License. +import functools import six import sys @@ -25,6 +26,8 @@ version_info = pbr.version.VersionInfo('openstack-placement') class DbCommands(object): + def __init__(self, config): + self.config = config def db_sync(self): # Let exceptions raise for now, they will go to stderr. @@ -35,9 +38,13 @@ class DbCommands(object): print(migration.version()) return 0 + def db_stamp(self): + migration.stamp(self.config.command.version) + return 0 -def add_db_command_parsers(subparsers): - command_object = DbCommands() + +def add_db_command_parsers(subparsers, config): + command_object = DbCommands(config) # If we set False here, we avoid having an exit during the parse # args part of CONF processing and we can thus print out meaningful @@ -58,20 +65,27 @@ def add_db_command_parsers(subparsers): 'version', help=help, description=help) version_parser.set_defaults(func=command_object.db_version) + help = _('Stamp the revision table with the given version.') + stamp_parser = db_parser.add_parser('stamp', help=help, description=help) + stamp_parser.add_argument('version', help=_('the version to stamp')) + stamp_parser.set_defaults(func=command_object.db_stamp) -def setup_commands(): + +def setup_commands(config): # This is a separate method because it facilitates unit testing. # Use an additional SubCommandOpt and parser for each new sub command. + add_db_cmd_parsers = functools.partial( + add_db_command_parsers, config=config) command_opt = cfg.SubCommandOpt( 'db', dest='command', title='Command', help=_('Available DB commands'), - handler=add_db_command_parsers) + handler=add_db_cmd_parsers) return [command_opt] def main(): config = cfg.ConfigOpts() conf.register_opts(config) - command_opts = setup_commands() + command_opts = setup_commands(config) config.register_cli_opts(command_opts) config(sys.argv[1:], project='placement', version=version_info.version_string(), diff --git a/placement/db/sqlalchemy/migration.py b/placement/db/sqlalchemy/migration.py index 79f9c9e1c..26303ac82 100644 --- a/placement/db/sqlalchemy/migration.py +++ b/placement/db/sqlalchemy/migration.py @@ -65,3 +65,13 @@ def upgrade(revision, config=None): revision = revision or "head" config = config or _alembic_config() alembic.command.upgrade(config, revision) + + +def stamp(version, config=None): + """Used for stamp the database version. + + :param version: Database version to stamp + :type version: string + """ + config = config or _alembic_config() + alembic.command.stamp(config, version) diff --git a/placement/tests/unit/cmd/test_manage.py b/placement/tests/unit/cmd/test_manage.py index ab945c904..0e2d81090 100644 --- a/placement/tests/unit/cmd/test_manage.py +++ b/placement/tests/unit/cmd/test_manage.py @@ -37,7 +37,7 @@ class TestCommandParsers(testtools.TestCase): # We don't use a database, but we need to set the opt as # it's required for a valid config. conf_fixture.config(group="placement_database", connection='sqlite://') - command_opts = manage.setup_commands() + command_opts = manage.setup_commands(conf_fixture) # Command line opts must be registered on the conf_fixture, otherwise # they carry over globally. conf_fixture.register_cli_opts(command_opts) @@ -50,6 +50,7 @@ class TestCommandParsers(testtools.TestCase): for command, args in [ ('db_version', ['db', 'version']), ('db_sync', ['db', 'sync']), + ('db_stamp', ['db', 'stamp', 'b4ed3a175331']), ]: with mock.patch('placement.cmd.manage.DbCommands.' + command) as mock_command: @@ -100,6 +101,6 @@ class TestCommandParsers(testtools.TestCase): self.output.stderr.seek(0) if six.PY2: - self.assertIn('{sync,version}', self.output.stderr.read()) + self.assertIn('{sync,version,stamp}', self.output.stderr.read()) else: - self.assertIn('{sync,version}', self.output.stdout.read()) + self.assertIn('{sync,version,stamp}', self.output.stdout.read())