[openstack-glance/f16] Cherry pick some upstream fixes for DB upgrade issues (#809430)

Mark McLoughlin markmc at fedoraproject.org
Wed Apr 4 11:22:11 UTC 2012


commit 905d4d5dbaf16ac02e35dad85447e8c96eb3ae54
Author: Mark McLoughlin <markmc at redhat.com>
Date:   Wed Apr 4 12:21:25 2012 +0100

    Cherry pick some upstream fixes for DB upgrade issues (#809430)
    
    - Allow specifying the current version in 'glance-manage version_control'
    - Don't use BIGINT in sqlite DBs

 ...fying-the-current-version-in-glance-manag.patch |  241 ++++++++++++++++++++
 ...-Compile-BigInteger-to-INTEGER-for-sqlite.patch |   86 +++++++
 openstack-glance.spec                              |   11 +-
 3 files changed, 337 insertions(+), 1 deletions(-)
---
diff --git a/0003-Allow-specifying-the-current-version-in-glance-manag.patch b/0003-Allow-specifying-the-current-version-in-glance-manag.patch
new file mode 100644
index 0000000..0819641
--- /dev/null
+++ b/0003-Allow-specifying-the-current-version-in-glance-manag.patch
@@ -0,0 +1,241 @@
+From 8d251ad2ad0936323f790585c7d19cae4a5dc925 Mon Sep 17 00:00:00 2001
+From: Mark McLoughlin <markmc at redhat.com>
+Date: Tue, 27 Mar 2012 12:23:47 +0100
+Subject: [PATCH] Allow specifying the current version in 'glance-manage
+ version_control'
+
+Fixes bug #966242
+
+The version_control command is a bit useless since you can't actually
+specify what version to  use and it defaults to version=0.
+
+Allow the user to specify a version:
+
+  $> glance-manage version_control 9 # set the diablo version
+
+and default to the latest version if none is specified.
+
+Also, allow db_sync to be supplied a version for the case where we're
+upgrading an unversioned DB.
+
+Finally, re-work the argument handling in glance-manage to more easily
+handle optional args.
+
+The tests are extended to test using db_sync for upgrades and to test
+placing an existing database under version control.
+
+Change-Id: I231dc710554198bfd1fdcb82c3c3768963f64bd8
+---
+ bin/glance-manage                    |   29 ++++++++-------------
+ glance/registry/db/migration.py      |   20 ++++++++++----
+ glance/tests/unit/test_migrations.py |   46 +++++++++++++++++++++++++++++----
+ 3 files changed, 65 insertions(+), 30 deletions(-)
+
+diff --git a/bin/glance-manage b/bin/glance-manage
+index f635232..138fdac 100755
+--- a/bin/glance-manage
++++ b/bin/glance-manage
+@@ -67,42 +67,35 @@ def do_db_version(options, args):
+ 
+ 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)
++    version = args.pop(0) if args else None
++    glance.registry.db.migration.upgrade(options, version)
+ 
+ 
+ def do_downgrade(options, args):
+     """Downgrade the database's migration level"""
+-    try:
+-        db_version = args[1]
+-    except IndexError:
++    if not args:
+         raise exception.MissingArgumentError(
+             "downgrade requires a version argument")
+-
+-    glance.registry.db.migration.downgrade(options, version=db_version)
++    version = args.pop(0)
++    glance.registry.db.migration.downgrade(options, version)
+ 
+ 
+ def do_version_control(options, args):
+     """Place a database under migration control"""
+-    glance.registry.db.migration.version_control(options)
++    version = args.pop(0) if args else None
++    glance.registry.db.migration.version_control(options, version)
+ 
+ 
+ def do_db_sync(options, args):
+     """Place a database under migration control and upgrade"""
+-    try:
+-        db_version = args[1]
+-    except IndexError:
+-        db_version = None
+-    glance.registry.db.migration.db_sync(options, version=db_version)
++    version = args.pop(0) if args else None
++    current_version = args.pop(0) if args else None
++    glance.registry.db.migration.db_sync(options, version, current_version)
+ 
+ 
+ def dispatch_cmd(options, args):
+     """Search for do_* cmd in this module and then run it"""
+-    cmd = args[0]
++    cmd = args.pop(0)
+     try:
+         cmd_func = globals()['do_%s' % cmd]
+     except KeyError:
+diff --git a/glance/registry/db/migration.py b/glance/registry/db/migration.py
+index 253107b..0ebd666 100644
+--- a/glance/registry/db/migration.py
++++ b/glance/registry/db/migration.py
+@@ -25,6 +25,7 @@ try:
+     from migrate.versioning import exceptions as versioning_exceptions
+ except ImportError:
+     from migrate import exceptions as versioning_exceptions
++from migrate.versioning import repository as versioning_repository
+ 
+ from glance.common import exception
+ 
+@@ -82,7 +83,7 @@ def downgrade(options, version):
+     return versioning_api.downgrade(sql_connection, repo_path, version)
+ 
+ 
+-def version_control(options):
++def version_control(options, version=None):
+     """
+     Place a database under migration control
+ 
+@@ -90,14 +91,14 @@ def version_control(options):
+     """
+     sql_connection = options['sql_connection']
+     try:
+-        _version_control(options)
++        _version_control(options, version)
+     except versioning_exceptions.DatabaseAlreadyControlledError, e:
+         msg = (_("database '%(sql_connection)s' is already under migration "
+                "control") % locals())
+         raise exception.DatabaseMigrationError(msg)
+ 
+ 
+-def _version_control(options):
++def _version_control(options, version=None):
+     """
+     Place a database under migration control
+ 
+@@ -105,20 +106,27 @@ def _version_control(options):
+     """
+     repo_path = get_migrate_repo_path()
+     sql_connection = options['sql_connection']
+-    return versioning_api.version_control(sql_connection, repo_path)
++    if version is None:
++        version = versioning_repository.Repository(repo_path).latest
++    return versioning_api.version_control(sql_connection, repo_path, version)
+ 
+ 
+-def db_sync(options, version=None):
++def db_sync(options, version=None, current_version=None):
+     """
+     Place a database under migration control and perform an upgrade
+ 
+     :param options: options dict
+     :retval version number
+     """
++    sql_connection = options['sql_connection']
+     try:
+-        _version_control(options)
++        _version_control(options, current_version)
+     except versioning_exceptions.DatabaseAlreadyControlledError, e:
+         pass
++        if current_version is not None:
++            msg = (_("database '%(sql_connection)s' is already under "
++                     "migration control") % locals())
++            raise exception.DatabaseMigrationError(msg)
+ 
+     upgrade(options, version=version)
+ 
+diff --git a/glance/tests/unit/test_migrations.py b/glance/tests/unit/test_migrations.py
+index 0ab4755..a6e3bcb 100644
+--- a/glance/tests/unit/test_migrations.py
++++ b/glance/tests/unit/test_migrations.py
+@@ -35,6 +35,7 @@ from sqlalchemy import *
+ from sqlalchemy.pool import NullPool
+ 
+ from glance.common import exception
++from glance.registry.db import models
+ import glance.registry.db.migration as migration_api
+ from glance.tests.utils import execute
+ 
+@@ -127,7 +128,39 @@ class TestMigrations(unittest.TestCase):
+             options = {'sql_connection': TestMigrations.TEST_DATABASES[key]}
+             self._walk_versions(options)
+ 
+-    def _walk_versions(self, options):
++    def test_version_control_existing_db(self):
++        """
++        Creates a DB without version control information, places it
++        under version control and checks that it can be upgraded
++        without errors.
++        """
++        for key, engine in self.engines.items():
++            #conf = utils.TestConfigOpts({
++            #        'sql_connection': TestMigrations.TEST_DATABASES[key]})
++            #conf.register_opt(cfg.StrOpt('sql_connection'))
++            options = {'sql_connection': TestMigrations.TEST_DATABASES[key]}
++            self._create_unversioned_001_db(engine)
++            self._walk_versions(options, initial_version=1)
++
++    def _create_unversioned_001_db(self, engine):
++        # Create the initial version of the images table
++        meta = MetaData()
++        meta.bind = engine
++        images_001 = Table('images', meta,
++            Column('id', models.Integer, primary_key=True),
++            Column('name', String(255)),
++            Column('type', String(30)),
++            Column('size', Integer),
++            Column('status', String(30)),
++            Column('is_public', Boolean, default=False),
++            Column('location', Text),
++            Column('created_at', DateTime(), nullable=False),
++            Column('updated_at', DateTime()),
++            Column('deleted_at', DateTime()),
++            Column('deleted', Boolean(), nullable=False, default=False))
++        images_001.create()
++
++    def _walk_versions(self, options, initial_version=0):
+         # Determine latest version script from the repo, then
+         # upgrade from 1 through to the latest, with no data
+         # in the databases. This just checks that the schema itself
+@@ -138,13 +171,14 @@ class TestMigrations(unittest.TestCase):
+                           migration_api.db_version,
+                           options)
+         # Place the database under version control
+-        migration_api.version_control(options)
++        migration_api.version_control(options, version=initial_version)
+ 
+         cur_version = migration_api.db_version(options)
+-        self.assertEqual(0, cur_version)
++        self.assertEqual(initial_version, cur_version)
+ 
+-        for version in xrange(1, TestMigrations.REPOSITORY.latest + 1):
+-            migration_api.upgrade(options, version)
++        for version in xrange(initial_version + 1,
++                              TestMigrations.REPOSITORY.latest + 1):
++            migration_api.db_sync(options, version)
+             cur_version = migration_api.db_version(options)
+             self.assertEqual(cur_version, version)
+ 
+@@ -169,7 +203,7 @@ class TestMigrations(unittest.TestCase):
+             self._no_data_loss_2_to_3_to_2(engine, options)
+ 
+     def _no_data_loss_2_to_3_to_2(self, engine, options):
+-        migration_api.version_control(options)
++        migration_api.version_control(options, version=0)
+         migration_api.upgrade(options, 2)
+ 
+         cur_version = migration_api.db_version(options)
diff --git a/0004-Compile-BigInteger-to-INTEGER-for-sqlite.patch b/0004-Compile-BigInteger-to-INTEGER-for-sqlite.patch
new file mode 100644
index 0000000..be022b7
--- /dev/null
+++ b/0004-Compile-BigInteger-to-INTEGER-for-sqlite.patch
@@ -0,0 +1,86 @@
+From 571c8c197b2da6bb93adac5d7f71cdac44894782 Mon Sep 17 00:00:00 2001
+From: Eoghan Glynn <eglynn at redhat.com>
+Date: Mon, 2 Apr 2012 18:55:35 +0100
+Subject: [PATCH] Compile BigInteger to INTEGER for sqlite
+
+Fixes bug 966243
+
+Ensure BigInteger does not map to BIGINT for an auto-created
+sqlite registry DB, as this type is not supported by sqlite.
+
+Change-Id: I61f44fbe50ea406d2d593f8f53cab5da3af2222a
+---
+ glance/registry/db/models.py           |    6 +++++
+ glance/tests/functional/test_sqlite.py |   39 ++++++++++++++++++++++++++++++++
+ 2 files changed, 45 insertions(+), 0 deletions(-)
+ create mode 100644 glance/tests/functional/test_sqlite.py
+
+diff --git a/glance/registry/db/models.py b/glance/registry/db/models.py
+index a66bc67..c6266b6 100644
+--- a/glance/registry/db/models.py
++++ b/glance/registry/db/models.py
+@@ -27,6 +27,7 @@ from sqlalchemy.orm import relationship, backref, exc, object_mapper, validates
+ from sqlalchemy import Column, Integer, String, BigInteger
+ from sqlalchemy import ForeignKey, DateTime, Boolean, Text
+ from sqlalchemy import UniqueConstraint
++from sqlalchemy.ext.compiler import compiles
+ from sqlalchemy.ext.declarative import declarative_base
+ 
+ import glance.registry.db.api
+@@ -35,6 +36,11 @@ from glance.common import exception
+ BASE = declarative_base()
+ 
+ 
++ at compiles(BigInteger, 'sqlite')
++def compile_big_int_sqlite(type_, compiler, **kw):
++    return 'INTEGER'
++
++
+ class ModelBase(object):
+     """Base class for Nova and Glance Models"""
+     __table_args__ = {'mysql_engine': 'InnoDB'}
+diff --git a/glance/tests/functional/test_sqlite.py b/glance/tests/functional/test_sqlite.py
+new file mode 100644
+index 0000000..4cfff6a
+--- /dev/null
++++ b/glance/tests/functional/test_sqlite.py
+@@ -0,0 +1,39 @@
++# vim: tabstop=4 shiftwidth=4 softtabstop=4
++
++# Copyright 2012 Red Hat, Inc
++# 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.
++
++"""Functional test cases for sqlite-specific logic"""
++
++
++from glance.tests import functional
++from glance.tests.utils import execute
++
++
++class TestSqlite(functional.FunctionalTest):
++    """Functional tests for sqlite-specific logic"""
++
++    @functional.runs_sql
++    def test_big_int_mapping(self):
++        """Ensure BigInteger not mapped to BIGINT"""
++        self.cleanup()
++        self.start_servers(**self.__dict__.copy())
++
++        cmd = "sqlite3 tests.sqlite '.schema'"
++        exitcode, out, err = execute(cmd, raise_error=True)
++
++        self.assertFalse('BIGINT' in out)
++
++        self.stop_servers()
diff --git a/openstack-glance.spec b/openstack-glance.spec
index 5f1b693..773a800 100644
--- a/openstack-glance.spec
+++ b/openstack-glance.spec
@@ -1,6 +1,6 @@
 Name:             openstack-glance
 Version:          2011.3.1
-Release:          3%{?dist}
+Release:          4%{?dist}
 Summary:          OpenStack Image Service
 
 Group:            Applications/System
@@ -16,6 +16,8 @@ Source3:          openstack-glance.logrotate
 #
 Patch0001: 0001-Always-reference-the-glance-module-from-the-package-.patch
 Patch0002: 0002-Don-t-access-the-net-while-building-docs.patch
+Patch0003: 0003-Allow-specifying-the-current-version-in-glance-manag.patch
+Patch0004: 0004-Compile-BigInteger-to-INTEGER-for-sqlite.patch
 
 BuildArch:        noarch
 BuildRequires:    python2-devel
@@ -99,6 +101,8 @@ This package contains documentation files for glance.
 
 %patch0001 -p1
 %patch0002 -p1
+%patch0003 -p1
+%patch0004 -p1
 
 sed -i 's|\(sql_connection = sqlite:///\)\(glance.sqlite\)|\1%{_sharedstatedir}/glance/\2|' etc/glance-registry.conf
 
@@ -211,6 +215,11 @@ fi
 %doc doc/build/html
 
 %changelog
+* Wed Apr  4 2012 Mark McLoughlin <markmc at redhat.com> - 2011.3.1-4
+- Cherry pick some upstream fixes for DB upgrade issues (#809430)
+- Allow specifying the current version in 'glance-manage version_control'
+- Don't use BIGINT in sqlite DBs
+
 * Mon Feb 13 2012 Russell Bryant <rbryant at redhat.com> - 2011.3.1-3
 - Add dependency on python-crypto. (rhbz#789943)
 


More information about the scm-commits mailing list