Adding migration management commands

This commit is contained in:
Rick Harris 2011-02-02 01:43:16 +00:00
parent 8a084f6ff5
commit 9c5290bcb5
11 changed files with 262 additions and 0 deletions

View File

@ -6,5 +6,6 @@ include tests/stubs.py
include tests/test_data.py
include tests/utils.py
include run_tests.py
include glance/registry/db/migrate_repo/migrate.cfg
graft doc
graft tools

126
bin/glance-manage Executable file
View File

@ -0,0 +1,126 @@
#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# Copyright 2011 OpenStack LLC.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""
Glance Management Utility
"""
# FIXME(sirp): When we have glance-admin we can consider merging this into it
# Perhaps for consistency with Nova, we would then rename glance-admin ->
# glance-manage (or the other way around)
import optparse
import os
import sys
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(ROOT_DIR)
from glance import version as glance_version
from glance.common import config
from glance.common import exception
import glance.registry.db
import glance.registry.db.migration
def create_options(parser):
"""
Sets up the CLI and config-file options that may be
parsed and program commands.
:param parser: The option parser
"""
parser.add_option('-v', '--verbose', default=False, dest="verbose",
action="store_true",
help="Print more verbose output")
parser.add_option('-d', '--debug', default=False, dest="debug",
action="store_true",
help="Print debugging output")
config.add_log_options('glance-manage', parser)
glance.registry.db.add_options(parser)
def do_db_version(options, args):
"""Print database's current migration level"""
print glance.registry.db.migration.db_version(options)
def do_upgrade(options, args):
"""Upgrade the database's migration level"""
try:
db_version = args[1]
except IndexError:
db_version = None
glance.registry.db.migration.upgrade(options, version=db_version)
def do_downgrade(options, args):
"""Downgrade the database's migration level"""
try:
db_version = args[1]
except IndexError:
raise exception.MissingArgumentError(
"downgrade requires a version argument")
glance.registry.db.migration.downgrade(options, version=db_version)
def do_version_control(options, args):
"""Place a database under migration control"""
glance.registry.db.migration.version_control(options)
def dispatch_cmd(options, args):
"""Search for do_* cmd in this module and then run it"""
cmd = args[0]
try:
cmd_func = globals()['do_%s' % cmd]
except KeyError:
sys.exit("ERROR: unrecognized command '%s'" % cmd)
try:
cmd_func(options, args)
except exception.Error, e:
sys.exit("ERROR: %s" % e)
def main():
version = '%%prog %s' % glance_version.version_string()
usage = "%prog [options] <cmd>"
oparser = optparse.OptionParser(usage, version=version)
create_options(oparser)
(options, args) = config.parse_options(oparser)
try:
config.setup_logging(options)
except RuntimeError, e:
sys.exit("ERROR: %s" % e)
if not args:
oparser.print_usage()
sys.exit(1)
dispatch_cmd(options, args)
if __name__ == '__main__':
main()

View File

@ -33,6 +33,9 @@ Kernel-outside:
<filename> <name>
"""
# FIXME(sirp): This can be merged into glance-admin when that becomes
# available
import argparse
import pprint
import sys

View File

@ -75,6 +75,14 @@ class BadInputError(Exception):
pass
class MissingArgumentError(Error):
pass
class DatabaseMigrationError(Error):
pass
def wrap_exception(f):
def _wrap(*args, **kw):
try:

View File

@ -0,0 +1,4 @@
This is a database migration repository.
More information at
http://code.google.com/p/sqlalchemy-migrate/

View File

@ -0,0 +1 @@
# template repository default module

View File

@ -0,0 +1,3 @@
#!/usr/bin/env python
from migrate.versioning.shell import main
main(debug='False')

View File

@ -0,0 +1,20 @@
[db_settings]
# Used to identify which repository this database is versioned under.
# You can use the name of your project.
repository_id=Glance Migrations
# The name of the database table used to track the schema version.
# This name shouldn't already be used by your project.
# If this is changed once a database is under version control, you'll need to
# change the table name in each database too.
version_table=migrate_version
# When committing a change script, Migrate will attempt to generate the
# sql for all supported databases; normally, if one of them fails - probably
# because you don't have that database installed - it is ignored and the
# commit continues, perhaps ending successfully.
# Databases in this list MUST compile successfully during a commit, or the
# entire commit will fail. List the databases your application will actually
# be using to ensure your updates to that database work properly.
# This must be a list; example: ['postgres','sqlite']
required_dbs=[]

View File

@ -0,0 +1 @@
# template repository default versions module

View File

@ -0,0 +1,94 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 OpenStack LLC.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import logging
import os
from migrate.versioning import api as versioning_api
from migrate.versioning import exceptions as versioning_exceptions
from glance.common import exception
def db_version(options):
"""Return the database's current migration number
:param options: options dict
:retval version number
"""
repo_path = _find_migrate_repo()
sql_connection = options['sql_connection']
try:
return versioning_api.db_version(sql_connection, repo_path)
except versioning_exceptions.DatabaseNotControlledError, e:
msg = ("database '%(sql_connection)s' is not under migration control"
% locals())
raise exception.DatabaseMigrationError(msg)
def upgrade(options, version=None):
"""Upgrade the database's current migration level
:param options: options dict
:param version: version to upgrade (defaults to latest)
:retval version number
"""
db_version(options) # Ensure db is under migration control
repo_path = _find_migrate_repo()
sql_connection = options['sql_connection']
version_str = version or 'latest'
logging.info("Upgrading %(sql_connection)s to version %(version_str)s" %
locals())
return versioning_api.upgrade(sql_connection, repo_path, version)
def downgrade(options, version):
"""Downgrade the database's current migration level
:param options: options dict
:param version: version to downgrade to
:retval version number
"""
db_version(options) # Ensure db is under migration control
repo_path = _find_migrate_repo()
sql_connection = options['sql_connection']
logging.info("Downgrading %(sql_connection)s to version %(version)s" %
locals())
return versioning_api.downgrade(sql_connection, repo_path, version)
def version_control(options):
"""Place a database under migration control
:param options: options dict
"""
repo_path = _find_migrate_repo()
sql_connection = options['sql_connection']
try:
versioning_api.version_control(sql_connection, repo_path)
except versioning_exceptions.DatabaseAlreadyControlledError, e:
msg = ("database '%(sql_connection)s' is already under migration "
"control" % locals())
raise exception.DatabaseMigrationError(msg)
def _find_migrate_repo():
"""Get the path for the migrate repository."""
path = os.path.join(os.path.abspath(os.path.dirname(__file__)),
'migrate_repo')
assert os.path.exists(path)
return path

View File

@ -14,3 +14,4 @@ sphinx
argparse
mox==0.5.0
-f http://pymox.googlecode.com/files/mox-0.5.0.tar.gz
sqlalchemy-migrate>=0.6