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:
parent
4e28e4d9dc
commit
048a40c0b5
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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...
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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'])
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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."""
|
||||
|
|
|
@ -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."""
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
|
@ -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):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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',
|
||||
|
|
Loading…
Reference in New Issue