Use common Oslo database session

Use common oslo database code for work with session, connection, engines
instead of glance implementations.
Work with config options modified due to new common code config.
Removed unused glance code and tests for it.

Details:

glance/cmd/manage.py
- removed load load the glance-registry config. We load sql connection
  in common code now.

glance/db/sqlalchemy/api.py
- removed functions _wrap_db_error(), _is_db_connection_error(),
  _get_maker(), get_engine(), _ping_listener() and config
  `sql_connection_opt`. We have all these thigs in module
  `glance.openstack.common.db.sqlalchemy`.
- modified functions setup_db_env(), add_cli_options(), clear_db_env().
- functions _get_session() and get_engine() now call same functions
  from module `glance.openstack.common.db.sqlalchemy`.
- replaced sqlalchemy exception `sqlalchemy.exc.IntegrityError` to
  database duplicate exception - `db_exc.DBDuplicateEntry`.

Removed redundant tests - we use common code , so a lot of features was
already tested in Oslo.

Global variable _ENGINE was replaced by common function get_engine().

DocImpact
New database config options came from Oslo. See Table below
-------------------------------------------------------------------
Database config options ([group] option)
-----------------------------|-------------------------------------
       Glance                | Oslo
-----------------------------|-------------------------------------
[DEFAULT] sql_connection     |  [database] connection
[DEFAULT] sql_idle_timeout   |  [database] idle_timeout
[DEFAULT] sql_max_retries    |  [database] max_retries
[DEFAULT] sql_retry_interval |  [database] retry_interval
[DEFAULT] db_auto_create     |  NONE
[DEFAULT] sqlalchemy_debug   |  [database] connection_debug
[DEFAULT] use_tpool          |  [database] use_tpool
NONE                         |  [database] slave_connection
NONE                         |  [database] min_pool_size
NONE                         |  [database] max_pool_size
NONE                         |  [database] slave_connection
NONE                         |  [database] min_pool_size
NONE                         |  [database] max_pool_size
NONE                         |  [database] max_overflow
NONE                         |  [database] connection_trace
NONE                         |  [database] pool_timeout
-------------------------------------------------------------------

blueprint db-use-oslo-common-code

Change-Id: I3ff976545b1a82ff8df780e34128fcaf6f892b8c
This commit is contained in:
Boris Pavlovic 2013-11-22 16:19:50 +02:00
parent 4e28e4d9dc
commit 048a40c0b5
29 changed files with 45 additions and 460 deletions

View File

@ -36,7 +36,6 @@ class ImageDataController(object):
gateway=None):
if gateway is None:
db_api = db_api or glance.db.get_api()
db_api.setup_db_env()
store_api = store_api or glance.store
policy = policy_enforcer or glance.api.policy.Enforcer()
notifier = notifier or glance.notifier.Notifier()

View File

@ -34,7 +34,6 @@ class ImageMembersController(object):
def __init__(self, db_api=None, policy_enforcer=None, notifier=None,
store_api=None):
self.db_api = db_api or glance.db.get_api()
self.db_api.setup_db_env()
self.policy = policy_enforcer or policy.Enforcer()
self.notifier = notifier or glance.notifier.Notifier()
self.store_api = store_api or glance.store

View File

@ -30,7 +30,6 @@ class Controller(object):
def __init__(self, db_api=None, policy_enforcer=None, notifier=None,
store_api=None):
self.db_api = db_api or glance.db.get_api()
self.db_api.setup_db_env()
self.policy = policy_enforcer or policy.Enforcer()
self.notifier = notifier or glance.notifier.Notifier()
self.store_api = store_api or glance.store

View File

@ -44,7 +44,6 @@ class ImagesController(object):
def __init__(self, db_api=None, policy_enforcer=None, notifier=None,
store_api=None):
self.db_api = db_api or glance.db.get_api()
self.db_api.setup_db_env()
self.policy = policy_enforcer or policy.Enforcer()
self.notifier = notifier or glance.notifier.Notifier()
self.store_api = store_api or glance.store

View File

@ -43,7 +43,6 @@ class TasksController(object):
def __init__(self, db_api=None, policy_enforcer=None, notifier=None,
store_api=None):
self.db_api = db_api or glance.db.get_api()
self.db_api.setup_db_env()
self.policy = policy_enforcer or policy.Enforcer()
self.notifier = notifier or glance.notifier.Notifier()
self.store_api = store_api or glance.store

View File

@ -43,11 +43,11 @@ from oslo.config import cfg
from glance.common import config
from glance.common import exception
import glance.db.sqlalchemy.api
from glance.db.sqlalchemy import migration
from glance.openstack.common import log
CONF = cfg.CONF
CONF.import_group("database", "glance.openstack.common.db.sqlalchemy.session")
# Decorators for actions
@ -171,10 +171,6 @@ def methods_of(obj):
def main():
CONF.register_cli_opt(command_opt)
try:
# We load the glance-registry config section because
# sql_connection is only part of the glance registry.
glance.db.sqlalchemy.api.add_cli_options()
cfg_files = cfg.find_config_files(project='glance',
prog='glance-registry')
cfg_files.extend(cfg.find_config_files(project='glance',

View File

@ -27,7 +27,7 @@ import os
import sys
# Monkey patch socket and time
eventlet.patcher.monkey_patch(all=False, socket=True, time=True)
eventlet.patcher.monkey_patch(all=False, socket=True, time=True, thread=True)
# If ../glance/__init__.py exists, add ../ to Python search path, so that
# it will override what happens to be installed in /usr/(local/)lib/python...

View File

@ -18,7 +18,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import functools
from oslo.config import cfg
from glance.common import crypt
@ -27,26 +26,18 @@ import glance.domain
import glance.domain.proxy
from glance.openstack.common import importutils
db_opt = cfg.BoolOpt('use_tpool',
default=False,
help='Enable the use of thread pooling for '
'all DB API calls')
CONF = cfg.CONF
CONF.import_opt('metadata_encryption_key', 'glance.common.config')
CONF.register_opt(db_opt)
def get_api():
if not CONF.use_tpool:
return importutils.import_module(CONF.data_api)
return ThreadPoolWrapper(CONF.data_api)
return importutils.import_module(CONF.data_api)
def unwrap(db_api):
if not CONF.use_tpool:
return db_api
return db_api.unwrap()
return db_api
# attributes common to all models
BASE_MODEL_ATTRS = set(['id', 'created_at', 'updated_at', 'deleted_at',
@ -291,27 +282,6 @@ class ImageMemberRepo(object):
return image_member
class ThreadPoolWrapper(object):
def __init__(self, wrapped):
self.wrapped = importutils.import_module(wrapped)
def __getattr__(self, key):
original = getattr(self.wrapped, key)
if not callable(original):
return original
@functools.wraps(original)
def wrapper(*args, **kwargs):
from eventlet import tpool
output = tpool.execute(original, *args, **kwargs)
return output
return wrapper
def unwrap(self):
return self.wrapped
class TaskRepo(object):
def _format_task_from_db(self, db_task):

View File

@ -39,13 +39,6 @@ from glance.registry.client.v2 import api
LOG = logging.getLogger(__name__)
def setup_db_env():
"""
Setup configuration for database
"""
api.configure_registry_client()
def _get_client(func):
"""Injects a client instance to the each function

View File

@ -62,15 +62,6 @@ def reset():
}
def setup_db_env(*args, **kwargs):
"""
Setup global environment configuration variables.
We have no connection-oriented environment variables, so this is a NOOP.
"""
pass
def clear_db_env(*args, **kwargs):
"""
Setup global environment configuration variables.

View File

@ -22,25 +22,19 @@
"""Defines interface for DB access."""
import logging
import time
from oslo.config import cfg
import sqlalchemy
import sqlalchemy.orm as sa_orm
import sqlalchemy.sql as sa_sql
from glance.common import exception
from glance.db.sqlalchemy import migration
from glance.db.sqlalchemy import models
from glance.openstack.common.db import exception as db_exception
from glance.openstack.common.db.sqlalchemy import session
import glance.openstack.common.log as os_logging
from glance.openstack.common import timeutils
_ENGINE = None
_MAKER = None
_MAX_RETRIES = None
_RETRY_INTERVAL = None
BASE = models.BASE
sa_logger = None
LOG = os_logging.getLogger(__name__)
@ -49,87 +43,15 @@ LOG = os_logging.getLogger(__name__)
STATUSES = ['active', 'saving', 'queued', 'killed', 'pending_delete',
'deleted']
sql_connection_opt = cfg.StrOpt('sql_connection',
default='sqlite:///glance.sqlite',
secret=True,
metavar='CONNECTION',
help=_('A valid SQLAlchemy connection '
'string for the registry database. '
'Default: %(default)s'))
db_opts = [
cfg.IntOpt('sql_idle_timeout', default=3600,
help=_('Period in seconds after which SQLAlchemy should '
'reestablish its connection to the database.')),
cfg.IntOpt('sql_max_retries', default=60,
help=_('The number of times to retry a connection to the SQL'
'server.')),
cfg.IntOpt('sql_retry_interval', default=1,
help=_('The amount of time to wait (in seconds) before '
'attempting to retry the SQL connection.')),
cfg.BoolOpt('db_auto_create', default=False,
help=_('A boolean that determines if the database will be '
'automatically created.')),
cfg.BoolOpt('sqlalchemy_debug', default=False,
help=_('Enable debug logging in sqlalchemy which prints '
'every query and result'))
]
CONF = cfg.CONF
CONF.register_opt(sql_connection_opt)
CONF.register_opts(db_opts)
CONF.import_opt('debug', 'glance.openstack.common.log')
def add_cli_options():
"""Allows passing sql_connection as a CLI argument."""
# NOTE(flaper87): Find a better place / way for this.
CONF.unregister_opt(sql_connection_opt)
CONF.register_cli_opt(sql_connection_opt)
def _ping_listener(dbapi_conn, connection_rec, connection_proxy):
"""Ensures that MySQL connections checked out of the
pool are alive.
Borrowed from:
http://groups.google.com/group/sqlalchemy/msg/a4ce563d802c929f
"""
try:
dbapi_conn.cursor().execute('select 1')
except dbapi_conn.OperationalError as ex:
if ex.args[0] in (2006, 2013, 2014, 2045, 2055):
msg = 'Got mysql server has gone away: %s' % ex
LOG.warn(msg)
raise sqlalchemy.exc.DisconnectionError(msg)
else:
raise
def setup_db_env():
"""Setup global configuration for database."""
global sa_logger, _IDLE_TIMEOUT, _MAX_RETRIES, _RETRY_INTERVAL, _CONNECTION
_IDLE_TIMEOUT = CONF.sql_idle_timeout
_MAX_RETRIES = CONF.sql_max_retries
_RETRY_INTERVAL = CONF.sql_retry_interval
_CONNECTION = CONF.sql_connection
sa_logger = logging.getLogger('sqlalchemy.engine')
if CONF.sqlalchemy_debug:
sa_logger.setLevel(logging.DEBUG)
def clear_db_env():
"""
Unset global configuration variables for database.
"""
global _ENGINE, _MAKER, _MAX_RETRIES, _RETRY_INTERVAL, _CONNECTION
_ENGINE = None
_MAKER = None
_MAX_RETRIES = None
_RETRY_INTERVAL = None
session.cleanup()
def _check_mutate_authorization(context, image_ref):
@ -144,117 +66,8 @@ def _check_mutate_authorization(context, image_ref):
raise exc_class(msg)
def _get_session(autocommit=True, expire_on_commit=False):
"""Helper method to grab session."""
global _MAKER
if not _MAKER:
get_engine()
_get_maker(autocommit, expire_on_commit)
assert(_MAKER)
session = _MAKER()
return session
def get_engine():
"""Return a SQLAlchemy engine."""
"""May assign _ENGINE if not already assigned"""
global _ENGINE, sa_logger, _CONNECTION, _IDLE_TIMEOUT, _MAX_RETRIES,\
_RETRY_INTERVAL
if not _ENGINE:
tries = _MAX_RETRIES
retry_interval = _RETRY_INTERVAL
connection_dict = sqlalchemy.engine.url.make_url(_CONNECTION)
engine_args = {
'pool_recycle': _IDLE_TIMEOUT,
'echo': False,
'convert_unicode': True}
try:
_ENGINE = sqlalchemy.create_engine(_CONNECTION, **engine_args)
if 'mysql' in connection_dict.drivername:
sqlalchemy.event.listen(_ENGINE, 'checkout', _ping_listener)
_ENGINE.connect = _wrap_db_error(_ENGINE.connect)
_ENGINE.connect()
except Exception as err:
msg = _("Error configuring registry database with supplied "
"sql_connection. Got error: %s") % err
LOG.error(msg)
raise
sa_logger = logging.getLogger('sqlalchemy.engine')
if CONF.sqlalchemy_debug:
sa_logger.setLevel(logging.DEBUG)
if CONF.db_auto_create:
LOG.info(_('auto-creating glance registry DB'))
models.register_models(_ENGINE)
try:
migration.version_control()
except exception.DatabaseMigrationError:
# only arises when the DB exists and is under version control
pass
else:
LOG.info(_('not auto-creating glance registry DB'))
return _ENGINE
def _get_maker(autocommit=True, expire_on_commit=False):
"""Return a SQLAlchemy sessionmaker."""
"""May assign __MAKER if not already assigned"""
global _MAKER, _ENGINE
assert _ENGINE
if not _MAKER:
_MAKER = sa_orm.sessionmaker(bind=_ENGINE,
autocommit=autocommit,
expire_on_commit=expire_on_commit)
return _MAKER
def _is_db_connection_error(args):
"""Return True if error in connecting to db."""
# NOTE(adam_g): This is currently MySQL specific and needs to be extended
# to support Postgres and others.
# For the db2, the error code is -30081 since the db2 is still not ready
conn_err_codes = ('2002', '2003', '2006', '-30081')
for err_code in conn_err_codes:
if args.find(err_code) != -1:
return True
return False
def _wrap_db_error(f):
"""Retry DB connection. Copied from nova and modified."""
def _wrap(*args, **kwargs):
try:
return f(*args, **kwargs)
except sqlalchemy.exc.OperationalError as e:
if not _is_db_connection_error(e.args[0]):
raise
remaining_attempts = _MAX_RETRIES
while True:
LOG.warning(_('SQL connection failed. %d attempts left.'),
remaining_attempts)
remaining_attempts -= 1
time.sleep(_RETRY_INTERVAL)
try:
return f(*args, **kwargs)
except sqlalchemy.exc.OperationalError as e:
if (remaining_attempts == 0 or
not _is_db_connection_error(e.args[0])):
raise
except sqlalchemy.exc.DBAPIError:
raise
except sqlalchemy.exc.DBAPIError:
raise
_wrap.func_name = f.func_name
return _wrap
_get_session = session.get_session
get_engine = session.get_engine
def image_create(context, values):
@ -849,7 +662,7 @@ def _image_update(context, values, image_id, purge_props=False,
try:
image_ref.save(session=session)
except sqlalchemy.exc.IntegrityError:
except db_exception.DBDuplicateEntry:
raise exception.Duplicate("Image ID %s already exists!"
% values['id'])

View File

@ -37,7 +37,7 @@ def db_version():
:retval version number
"""
repo_path = get_migrate_repo_path()
sql_connection = CONF.sql_connection
sql_connection = CONF.database.connection
try:
return versioning_api.db_version(sql_connection, repo_path)
except versioning_exceptions.DatabaseNotControlledError as e:
@ -54,7 +54,7 @@ def upgrade(version=None):
"""
db_version() # Ensure db is under migration control
repo_path = get_migrate_repo_path()
sql_connection = CONF.sql_connection
sql_connection = CONF.database.connection
version_str = version or 'latest'
LOG.info(_("Upgrading database to version %s") %
version_str)
@ -70,7 +70,7 @@ def downgrade(version):
"""
db_version() # Ensure db is under migration control
repo_path = get_migrate_repo_path()
sql_connection = CONF.sql_connection
sql_connection = CONF.database.connection
LOG.info(_("Downgrading database to version %s") %
version)
return versioning_api.downgrade(sql_connection, repo_path, version)
@ -95,7 +95,7 @@ def _version_control(version):
run any migrations.
"""
repo_path = get_migrate_repo_path()
sql_connection = CONF.sql_connection
sql_connection = CONF.database.connection
if version is None:
version = versioning_repository.Repository(repo_path).latest
return versioning_api.version_control(sql_connection, repo_path, version)

View File

@ -79,17 +79,6 @@ class GlanceBase(models.ModelBase, models.TimestampMixin):
deleted_at = Column(DateTime)
deleted = Column(Boolean, nullable=False, default=False)
# TODO(vsergeyev): we should use save() method from
# models.ModelBase(), when we will use common
# oslo session
def save(self, session=None):
"""Save this object."""
# import api here to prevent circular dependency problem
import glance.db.sqlalchemy.api as db_api
session = session or db_api._get_session()
session.add(self)
session.flush()
def delete(self, session=None):
"""Delete this object."""
self.deleted = True

View File

@ -29,7 +29,6 @@ class Gateway(object):
def __init__(self, db_api=None, store_api=None, notifier=None,
policy_enforcer=None):
self.db_api = db_api or glance.db.get_api()
self.db_api.setup_db_env()
self.store_api = store_api or glance.store
self.notifier = notifier or glance.notifier.Notifier()
self.policy = policy_enforcer or policy.Enforcer()

View File

@ -91,7 +91,6 @@ class Controller(object):
def __init__(self):
self.db_api = glance.db.get_api()
self.db_api.setup_db_env()
def _get_images(self, context, filters, **params):
"""Get images, wrapping in exception if necessary."""

View File

@ -35,7 +35,6 @@ class Controller(object):
def __init__(self):
self.db_api = glance.db.get_api()
self.db_api.setup_db_env()
def is_image_sharable(self, context, image):
"""Return True if the image can be shared to others in this context."""

View File

@ -47,7 +47,6 @@ class Controller(rpc.Controller):
# NOTE(flaper87): Register the
# db_api as a resource to expose.
db_api = glance.db.get_api()
db_api.setup_db_env()
self.register(glance.db.unwrap(db_api))

View File

@ -1,84 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 OpenStack Foundation
# 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.
from mock import Mock
from oslo.config import cfg
import testtools
from glance import db as db_api
import glance.db
from glance.openstack.common import importutils
CONF = cfg.CONF
CONF.import_opt('use_tpool', 'glance.db')
CONF.import_opt('data_api', 'glance.db')
class DbApiTest(testtools.TestCase):
def test_get_dbapi_when_db_pool_is_enabled(self):
CONF.set_override('use_tpool', True)
dbapi = db_api.get_api()
self.assertTrue(isinstance(dbapi, db_api.ThreadPoolWrapper))
def test_get_dbapi_when_db_pool_is_disabled(self):
CONF.set_override('use_tpool', False)
dbapi = db_api.get_api()
self.assertFalse(isinstance(dbapi, db_api.ThreadPoolWrapper))
self.assertEqual(importutils.import_module(CONF.data_api), dbapi)
def test_unwrap_dbapi_when_db_pool_is_enabled(self):
CONF.set_override('use_tpool', False)
dbapi = db_api.get_api()
self.assertEqual(importutils.import_module(CONF.data_api),
glance.db.unwrap(dbapi))
def test_unwrap_dbapi_when_db_pool_is_disabled(self):
CONF.set_override('use_tpool', True)
dbapi = db_api.get_api()
self.assertEqual(importutils.import_module(CONF.data_api),
glance.db.unwrap(dbapi))
def method_for_test_1(*args, **kwargs):
return args, kwargs
class ThreadPoolWrapper(testtools.TestCase):
def test_thread_pool(self):
CONF.set_override('use_tpool', True)
CONF.set_override('data_api', 'glance.tests.functional.db.'
'test_db_api')
dbapi = db_api.get_api()
from eventlet import tpool
tpool.execute = Mock()
dbapi.method_for_test_1(1, 2, kwarg='arg')
tpool.execute.assert_called_with(method_for_test_1, 1, 2, kwarg='arg')
def test_unwrap(self):
CONF.set_override('use_tpool', True)
CONF.set_override('data_api', 'glance.tests.functional.db.'
'test_db_api')
dbapi = db_api.get_api()
self.assertEqual(importutils.import_module(CONF.data_api),
dbapi.unwrap())
def tearDown(self):
super(ThreadPoolWrapper, self).tearDown()
CONF.set_override('use_tpool', False)

View File

@ -13,19 +13,17 @@
# License for the specific language governing permissions and limitations
# under the License.
from glance.api import CONF
import glance.db.registry.api
from glance.registry.client.v2 import api
from glance.tests import functional
import glance.tests.functional.db as db_tests
from glance.tests.functional.db import base
def get_db(config):
config(sql_connection='sqlite://', verbose=False, debug=False)
CONF.set_override('data_api', 'glance.db.registry.api')
db_api = glance.db.get_api()
db_api.setup_db_env()
return db_api
config(group='database', connection='sqlite://')
api.configure_registry_client()
return glance.db.registry.api
def reset_db(db_api):

View File

@ -14,7 +14,6 @@
# License for the specific language governing permissions and limitations
# under the License.
from glance.api import CONF
import glance.db.sqlalchemy.api
from glance.db.sqlalchemy import models as db_models
import glance.tests.functional.db as db_tests
@ -22,17 +21,15 @@ from glance.tests.functional.db import base
def get_db(config):
config(sql_connection='sqlite://', verbose=False, debug=False)
CONF.set_override('data_api', 'glance.db.sqlalchemy.api')
db_api = glance.db.get_api()
db_api.setup_db_env()
db_api.get_engine()
config(connection='sqlite://', group='database')
config(verbose=False, debug=False)
db_api = glance.db.sqlalchemy.api
return db_api
def reset_db(db_api):
db_models.unregister_models(db_api._ENGINE)
db_models.register_models(db_api._ENGINE)
db_models.unregister_models(db_api.get_engine())
db_models.register_models(db_api.get_engine())
class TestSqlAlchemyDriver(base.TestDriver, base.DriverTests):

View File

@ -153,7 +153,7 @@ class ApiTest(test_utils.BaseTestCase):
def _setup_database(self):
sql_connection = 'sqlite:////%s/tests.sqlite' % self.test_dir
self.config(sql_connection=sql_connection)
self.config(connection=sql_connection, group='database')
glance.db.sqlalchemy.api.clear_db_env()
glance_db_env = 'GLANCE_DB_TEST_SQLITE_FILE'
if glance_db_env in os.environ:

View File

@ -158,7 +158,7 @@ class ApiTest(test_utils.BaseTestCase):
def _setup_database(self):
sql_connection = 'sqlite:////%s/tests.sqlite' % self.test_dir
self.config(sql_connection=sql_connection)
self.config(connection=sql_connection, group='database')
glance.db.sqlalchemy.api.clear_db_env()
glance_db_env = 'GLANCE_DB_TEST_SQLITE_FILE'
if glance_db_env in os.environ:

View File

@ -30,7 +30,8 @@ from glance.tests import utils as test_utils
CONF = cfg.CONF
CONF.import_opt('filesystem_store_datadir', 'glance.store.filesystem')
CONF.import_opt('sql_connection', 'glance.db.sqlalchemy.api')
CONF.import_opt('connection', 'glance.openstack.common.db.sqlalchemy.session',
group='database')
class StoreClearingUnitTest(test_utils.BaseTestCase):
@ -63,8 +64,9 @@ class IsolatedUnitTest(StoreClearingUnitTest):
super(IsolatedUnitTest, self).setUp()
self.test_dir = self.useFixture(fixtures.TempDir()).path
policy_file = self._copy_data_file('policy.json', self.test_dir)
self.config(sql_connection='sqlite://',
verbose=False,
self.config(connection='sqlite://',
group='database')
self.config(verbose=False,
debug=False,
default_store='filesystem',
filesystem_store_datadir=os.path.join(self.test_dir),

View File

@ -90,7 +90,6 @@ class TestGlanceAPI(base.IsolatedUnitTest):
'metadata': {}}],
'properties': {}}]
self.context = glance.context.RequestContext(is_admin=True)
db_api.setup_db_env()
db_api.get_engine()
self.destroy_fixtures()
self.create_fixtures()
@ -110,8 +109,8 @@ class TestGlanceAPI(base.IsolatedUnitTest):
def destroy_fixtures(self):
# Easiest to just drop the models and re-create them...
db_models.unregister_models(db_api._ENGINE)
db_models.register_models(db_api._ENGINE)
db_models.unregister_models(db_api.get_engine())
db_models.register_models(db_api.get_engine())
def _do_test_defaulted_format(self, format_key, format_value):
fixture_headers = {'x-image-meta-name': 'defaulted',
@ -3106,10 +3105,9 @@ class TestAPIProtectedProps(base.IsolatedUnitTest):
# turn on property protections
self.set_property_protections()
self.api = test_utils.FakeAuthMiddleware(router.API(self.mapper))
db_api.setup_db_env()
db_api.get_engine()
db_models.unregister_models(db_api._ENGINE)
db_models.register_models(db_api._ENGINE)
db_models.unregister_models(db_api.get_engine())
db_models.register_models(db_api.get_engine())
def tearDown(self):
"""Clear the test environment"""
@ -3118,8 +3116,8 @@ class TestAPIProtectedProps(base.IsolatedUnitTest):
def destroy_fixtures(self):
# Easiest to just drop the models and re-create them...
db_models.unregister_models(db_api._ENGINE)
db_models.register_models(db_api._ENGINE)
db_models.unregister_models(db_api.get_engine())
db_models.register_models(db_api.get_engine())
def _create_admin_image(self, props={}):
request = unit_test_utils.get_fake_request(path='/images')
@ -3823,10 +3821,9 @@ class TestAPIPropertyQuotas(base.IsolatedUnitTest):
super(TestAPIPropertyQuotas, self).setUp()
self.mapper = routes.Mapper()
self.api = test_utils.FakeAuthMiddleware(router.API(self.mapper))
db_api.setup_db_env()
db_api.get_engine()
db_models.unregister_models(db_api._ENGINE)
db_models.register_models(db_api._ENGINE)
db_models.unregister_models(db_api.get_engine())
db_models.register_models(db_api.get_engine())
def _create_admin_image(self, props={}):
request = unit_test_utils.get_fake_request(path='/images')

View File

@ -22,7 +22,6 @@ import uuid
from oslo.config import cfg
import routes
from sqlalchemy import exc
import webob
import glance.api.common
@ -46,57 +45,6 @@ UUID1 = _gen_uuid()
UUID2 = _gen_uuid()
class TestRegistryDb(test_utils.BaseTestCase):
def setUp(self):
"""Establish a clean test environment"""
super(TestRegistryDb, self).setUp()
self.setup_db()
def setup_db(self):
db_api.setup_db_env()
db_api.get_engine()
db_models.unregister_models(db_api._ENGINE)
db_models.register_models(db_api._ENGINE)
def test_bad_sql_connection(self):
"""
Test that a bad sql_connection option supplied to the registry
API controller results in a) an Exception being thrown and b)
a message being logged to the registry log file...
"""
self.config(verbose=True, debug=True, sql_connection='baddriver:///')
# We set this to None to trigger a reconfigure, otherwise
# other modules may have already correctly configured the DB
db_api._ENGINE = None
db_api._CONNECTION = None
db_api._MAKER = None
db_api.setup_db_env()
self.assertRaises((ImportError, exc.ArgumentError),
db_api.get_engine)
exc_raised = False
self.log_written = False
def fake_log_error(msg):
if 'Error configuring registry database' in msg:
self.log_written = True
self.stubs.Set(db_api.LOG, 'error', fake_log_error)
try:
api_obj = rserver.API(routes.Mapper())
api = test_utils.FakeAuthMiddleware(api_obj, is_admin=True)
req = webob.Request.blank('/images/%s' % _gen_uuid())
res = req.get_response(api)
except exc.ArgumentError:
exc_raised = True
except ImportError:
exc_raised = True
self.assertTrue(exc_raised)
self.assertTrue(self.log_written)
class TestRegistryAPI(base.IsolatedUnitTest, test_utils.RegistryAPIMixIn):
def setUp(self):
@ -121,7 +69,6 @@ class TestRegistryAPI(base.IsolatedUnitTest, test_utils.RegistryAPIMixIn):
min_disk=5, min_ram=256,
size=19, properties={})]
self.context = context.RequestContext(is_admin=True)
db_api.setup_db_env()
db_api.get_engine()
self.destroy_fixtures()
self.create_fixtures()
@ -1811,7 +1758,6 @@ class TestRegistryAPILocations(base.IsolatedUnitTest,
min_disk=5, min_ram=256,
size=19, properties={})]
self.context = context.RequestContext(is_admin=True)
db_api.setup_db_env()
db_api.get_engine()
self.destroy_fixtures()
self.create_fixtures()
@ -1914,10 +1860,9 @@ class TestSharability(test_utils.BaseTestCase):
self.controller = glance.registry.api.v1.members.Controller()
def setup_db(self):
db_api.setup_db_env()
db_api.get_engine()
db_models.unregister_models(db_api._ENGINE)
db_models.register_models(db_api._ENGINE)
db_models.unregister_models(db_api.get_engine())
db_models.register_models(db_api.get_engine())
def test_is_image_sharable_as_admin(self):
TENANT1 = str(uuid.uuid4())

View File

@ -55,7 +55,6 @@ class TestRegistryV1Client(base.IsolatedUnitTest, test_utils.RegistryAPIMixIn):
def setUp(self):
"""Establish a clean test environment"""
super(TestRegistryV1Client, self).setUp()
db_api.setup_db_env()
db_api.get_engine()
self.context = context.RequestContext(is_admin=True)

View File

@ -89,7 +89,6 @@ class TestRegistryRPC(base.IsolatedUnitTest):
'properties': {}}]
self.context = glance.context.RequestContext(is_admin=True)
db_api.setup_db_env()
db_api.get_engine()
self.destroy_fixtures()
self.create_fixtures()
@ -109,8 +108,8 @@ class TestRegistryRPC(base.IsolatedUnitTest):
def destroy_fixtures(self):
# Easiest to just drop the models and re-create them...
db_models.unregister_models(db_api._ENGINE)
db_models.register_models(db_api._ENGINE)
db_models.unregister_models(db_api.get_engine())
db_models.register_models(db_api.get_engine())
def test_show(self):
"""
@ -1366,13 +1365,3 @@ class TestRegistryRPC(base.IsolatedUnitTest):
memb_list = json.loads(res.body)[0]
self.assertEqual(len(memb_list), 0)
class TestRegistryRPCDBPoolEnabled(TestRegistryRPC):
def setUp(self):
CONF.set_override('use_tpool', True)
super(TestRegistryRPCDBPoolEnabled, self).setUp()
def tearDown(self):
super(TestRegistryRPCDBPoolEnabled, self).tearDown()
CONF.set_override('use_tpool', False)

View File

@ -64,7 +64,6 @@ class TestRegistryV2Client(base.IsolatedUnitTest,
def setUp(self):
"""Establish a clean test environment"""
super(TestRegistryV2Client, self).setUp()
db_api.setup_db_env()
db_api.get_engine()
self.context = context.RequestContext(is_admin=True)

View File

@ -418,8 +418,8 @@ class RegistryAPIMixIn(object):
image.write("chunk00000remainder")
def destroy_fixtures(self):
db_models.unregister_models(db_api._ENGINE)
db_models.register_models(db_api._ENGINE)
db_models.unregister_models(db_api.get_engine())
db_models.register_models(db_api.get_engine())
def get_fixture(self, **kwargs):
fixture = {'name': 'fake public image',