From 7e6319d95554413f1a0856603f434c9c60b8d256 Mon Sep 17 00:00:00 2001 From: AmalaBasha Date: Wed, 18 Sep 2013 18:52:47 +0530 Subject: [PATCH] glance-manage should work like nova-manage nova-manage supports subcommands of db, for nova-manage, eg) 'nova-manage db sync', glance manage however has individual commands like db_sync, db_version etc. This patch aims at adding the db operations as subcommands to db in glance-manage similar to nova and refactoring this bit of code in cmd/manage.py Fixes: bug 1213197 Change-Id: I6fad31766bc1cec2a666a7ebc8df5c732007c5f1 --- doc/source/configuring.rst | 2 +- doc/source/db.rst | 20 +-- doc/source/man/glancemanage.rst | 2 +- glance/cmd/manage.py | 132 +++++++++++++----- glance/tests/functional/__init__.py | 2 +- glance/tests/functional/test_glance_manage.py | 2 +- 6 files changed, 113 insertions(+), 47 deletions(-) diff --git a/doc/source/configuring.rst b/doc/source/configuring.rst index cc5d79176c..d6d971bef5 100644 --- a/doc/source/configuring.rst +++ b/doc/source/configuring.rst @@ -173,7 +173,7 @@ Optional. Default: ``1`` * ``db_auto_create=False`` Whether to automatically create the database tables. Otherwise you can -manually run `glance-manage db_sync`. +manually run `glance-manage db sync`. Optional. Default: ``False`` diff --git a/doc/source/db.rst b/doc/source/db.rst index 7aca0e296b..542bdd1b01 100644 --- a/doc/source/db.rst +++ b/doc/source/db.rst @@ -21,27 +21,31 @@ The default metadata driver for glance uses sqlalchemy, which implies there exists a backend database which must be managed. The ``glance-manage`` binary provides a set of commands for making this easier. +The commands should be executed as a subcommand of 'db': -Initializing an Empty Database ------------------------------- + glance-manage db - glance-manage db_sync -This will take an empty database and create the necessary tables. +Sync the Database +----------------- + + glance-manage db sync + +Place a database under migration control and upgrade, creating it first if necessary. Determining the Database Version -------------------------------- - glance-manage db_version + glance-manage db version -This will print the version of a glance database. +This will print the current migration level of a glance database. Upgrading an Existing Database ------------------------------ - glance-manage db_sync + glance-manage db upgrade This will take an existing database and upgrade it to the specified VERSION. @@ -49,7 +53,7 @@ This will take an existing database and upgrade it to the specified VERSION. Downgrading an Existing Database -------------------------------- - glance-manage downgrade + glance-manage db downgrade This will downgrade an existing database from the current version to the specified VERSION. diff --git a/doc/source/man/glancemanage.rst b/doc/source/man/glancemanage.rst index 8d8cf85953..57c5be5099 100644 --- a/doc/source/man/glancemanage.rst +++ b/doc/source/man/glancemanage.rst @@ -24,7 +24,7 @@ DESCRIPTION glance-manage is a utility for managing and configuring a Glance installation. One important use of glance-manage is to setup the database. To do this run:: - glance-manage db_sync + glance-manage db sync OPTIONS ======= diff --git a/glance/cmd/manage.py b/glance/cmd/manage.py index 4e092fd9f4..517b55e8e4 100755 --- a/glance/cmd/manage.py +++ b/glance/cmd/manage.py @@ -44,69 +44,130 @@ from oslo.config import cfg from glance.common import config from glance.common import exception import glance.db.sqlalchemy.api -import glance.db.sqlalchemy.migration +from glance.db.sqlalchemy import migration from glance.openstack.common import log CONF = cfg.CONF -def do_db_version(): - """Print database's current migration level""" - print(glance.db.sqlalchemy.migration.db_version()) +# Decorators for actions +def args(*args, **kwargs): + def _decorator(func): + func.__dict__.setdefault('args', []).insert(0, (args, kwargs)) + return func + return _decorator -def do_upgrade(): - """Upgrade the database's migration level""" - glance.db.sqlalchemy.migration.upgrade(CONF.command.version) +class DbCommands(object): + """Class for managing the db""" + + def __init__(self): + pass + + def version(self): + """Print database's current migration level""" + print(migration.db_version()) + + @args('--version', metavar='', help='Database version') + def upgrade(self, version=None): + """Upgrade the database's migration level""" + migration.upgrade(version) + + @args('--version', metavar='', help='Database version') + def downgrade(self, version=None): + """Downgrade the database's migration level""" + migration.downgrade(version) + + @args('--version', metavar='', help='Database version') + def version_control(self, version=None): + """Place a database under migration control""" + migration.version_control(version) + + @args('--version', metavar='', help='Database version') + @args('--current_version', metavar='', + help='Current Database version') + def sync(self, version=None, current_version=None): + """ + Place a database under migration control and upgrade, + creating first if necessary. + """ + migration.db_sync(version, current_version) -def do_downgrade(): - """Downgrade the database's migration level""" - glance.db.sqlalchemy.migration.downgrade(CONF.command.version) +def add_legacy_command_parsers(command_object, subparsers): - -def do_version_control(): - """Place a database under migration control""" - glance.db.sqlalchemy.migration.version_control(CONF.command.version) - - -def do_db_sync(): - """ - Place a database under migration control and upgrade, - creating first if necessary. - """ - glance.db.sqlalchemy.migration.db_sync(CONF.command.version, - CONF.command.current_version) - - -def add_command_parsers(subparsers): parser = subparsers.add_parser('db_version') - parser.set_defaults(func=do_db_version) + parser.set_defaults(action_fn=command_object.version) - parser = subparsers.add_parser('upgrade') - parser.set_defaults(func=do_upgrade) + parser = subparsers.add_parser('db_upgrade') + parser.set_defaults(action_fn=command_object.upgrade) parser.add_argument('version', nargs='?') - parser = subparsers.add_parser('downgrade') - parser.set_defaults(func=do_downgrade) + parser = subparsers.add_parser('db_downgrade') + parser.set_defaults(action_fn=command_object.downgrade) parser.add_argument('version') - parser = subparsers.add_parser('version_control') - parser.set_defaults(func=do_version_control) + parser = subparsers.add_parser('db_version_control') + parser.set_defaults(action_fn=command_object.version_control) parser.add_argument('version', nargs='?') parser = subparsers.add_parser('db_sync') - parser.set_defaults(func=do_db_sync) + parser.set_defaults(action_fn=command_object.sync) parser.add_argument('version', nargs='?') parser.add_argument('current_version', nargs='?') +def add_command_parsers(subparsers): + command_object = DbCommands() + + parser = subparsers.add_parser('db') + parser.set_defaults(command_object=command_object) + + category_subparsers = parser.add_subparsers(dest='action') + + for (action, action_fn) in methods_of(command_object): + parser = category_subparsers.add_parser(action) + + action_kwargs = [] + for args, kwargs in getattr(action_fn, 'args', []): + # FIXME(basha): hack to assume dest is the arg name without + # the leading hyphens if no dest is supplied + kwargs.setdefault('dest', args[0][2:]) + if kwargs['dest'].startswith('action_kwarg_'): + action_kwargs.append( + kwargs['dest'][len('action_kwarg_'):]) + else: + action_kwargs.append(kwargs['dest']) + kwargs['dest'] = 'action_kwarg_' + kwargs['dest'] + + parser.add_argument(*args, **kwargs) + + parser.set_defaults(action_fn=action_fn) + parser.set_defaults(action_kwargs=action_kwargs) + + parser.add_argument('action_args', nargs='*') + + add_legacy_command_parsers(command_object, subparsers) + + command_opt = cfg.SubCommandOpt('command', title='Commands', help='Available commands', handler=add_command_parsers) +def methods_of(obj): + """Get all callable methods of an object that don't start with underscore + + returns a list of tuples of the form (method_name, method) + """ + result = [] + for i in dir(obj): + if callable(getattr(obj, i)) and not i.startswith('_'): + result.append((i, getattr(obj, i))) + return result + + def main(): CONF.register_cli_opt(command_opt) try: @@ -125,7 +186,8 @@ def main(): sys.exit("ERROR: %s" % e) try: - CONF.command.func() + + CONF.command.action_fn() except exception.GlanceException as e: sys.exit("ERROR: %s" % e) diff --git a/glance/tests/functional/__init__.py b/glance/tests/functional/__init__.py index b730e41f98..3236a21c18 100644 --- a/glance/tests/functional/__init__.py +++ b/glance/tests/functional/__init__.py @@ -215,7 +215,7 @@ class Server(object): os.system('cp %s %s/tests.sqlite' % (db_location, self.test_dir)) else: - cmd = ('%s -m glance.cmd.manage --config-file %s db_sync' % + cmd = ('%s -m glance.cmd.manage --config-file %s db sync' % (sys.executable, conf_filepath)) execute(cmd, no_venv=self.no_venv, exec_env=self.exec_env, expect_exit=True) diff --git a/glance/tests/functional/test_glance_manage.py b/glance/tests/functional/test_glance_manage.py index f1c6b60ffc..3ecdef7483 100644 --- a/glance/tests/functional/test_glance_manage.py +++ b/glance/tests/functional/test_glance_manage.py @@ -44,7 +44,7 @@ class TestGlanceManage(functional.FunctionalTest): conf_file.write(self.connection) conf_file.flush() - cmd = ('%s -m glance.cmd.manage --config-file %s db_sync' % + cmd = ('%s -m glance.cmd.manage --config-file %s db sync' % (sys.executable, self.conf_filepath)) execute(cmd, raise_error=True)