Skip to content

Commit

Permalink
Adding migration management commands
Browse files Browse the repository at this point in the history
  • Loading branch information
rconradharris committed Feb 2, 2011
1 parent 8a084f6 commit 9c5290b
Show file tree
Hide file tree
Showing 11 changed files with 262 additions and 0 deletions.
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 126 additions & 0 deletions bin/glance-manage
Original file line number Diff line number Diff line change
@@ -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()
3 changes: 3 additions & 0 deletions bin/glance-upload
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions glance/common/exception.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
4 changes: 4 additions & 0 deletions glance/registry/db/migrate_repo/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
This is a database migration repository.

More information at
http://code.google.com/p/sqlalchemy-migrate/
1 change: 1 addition & 0 deletions glance/registry/db/migrate_repo/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# template repository default module
3 changes: 3 additions & 0 deletions glance/registry/db/migrate_repo/manage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env python
from migrate.versioning.shell import main
main(debug='False')
20 changes: 20 additions & 0 deletions glance/registry/db/migrate_repo/migrate.cfg
Original file line number Diff line number Diff line change
@@ -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=[]
1 change: 1 addition & 0 deletions glance/registry/db/migrate_repo/versions/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# template repository default versions module
94 changes: 94 additions & 0 deletions glance/registry/db/migration.py
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions tools/pip-requires
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 9c5290b

Please sign in to comment.