Merge "Use oslo database code"
This commit is contained in:
@@ -80,6 +80,7 @@ from nova.db import migration
|
||||
from nova import exception
|
||||
from nova.openstack.common import cfg
|
||||
from nova.openstack.common import cliutils
|
||||
from nova.openstack.common.db.sqlalchemy import session as db_session
|
||||
from nova.openstack.common import importutils
|
||||
from nova.openstack.common import log as logging
|
||||
from nova.openstack.common import rpc
|
||||
@@ -831,7 +832,7 @@ class InstanceTypeCommands(object):
|
||||
except exception.InstanceTypeNotFound:
|
||||
print _("Valid instance type name is required")
|
||||
sys.exit(1)
|
||||
except exception.DBError, e:
|
||||
except db_session.DBError, e:
|
||||
print _("DB Error: %s") % e
|
||||
sys.exit(2)
|
||||
except Exception:
|
||||
@@ -848,7 +849,7 @@ class InstanceTypeCommands(object):
|
||||
inst_types = instance_types.get_all_types()
|
||||
else:
|
||||
inst_types = instance_types.get_instance_type_by_name(name)
|
||||
except exception.DBError, e:
|
||||
except db_session.DBError, e:
|
||||
_db_error(e)
|
||||
if isinstance(inst_types.values()[0], dict):
|
||||
for k, v in inst_types.iteritems():
|
||||
@@ -879,7 +880,7 @@ class InstanceTypeCommands(object):
|
||||
ext_spec)
|
||||
print _("Key %(key)s set to %(value)s on instance"
|
||||
" type %(name)s") % locals()
|
||||
except exception.DBError, e:
|
||||
except db_session.DBError, e:
|
||||
_db_error(e)
|
||||
|
||||
@args('--name', dest='name', metavar='<name>',
|
||||
@@ -902,7 +903,7 @@ class InstanceTypeCommands(object):
|
||||
key)
|
||||
|
||||
print _("Key %(key)s on instance type %(name)s unset") % locals()
|
||||
except exception.DBError, e:
|
||||
except db_session.DBError, e:
|
||||
_db_error(e)
|
||||
|
||||
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
# 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 2010-2011 OpenStack LLC.
|
||||
# Copyright 2012 Justin Santa Barbara
|
||||
# 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.
|
||||
|
||||
"""Implementation of paginate query."""
|
||||
|
||||
import sqlalchemy
|
||||
|
||||
from nova import exception
|
||||
from nova.openstack.common import log as logging
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# copy from glance/db/sqlalchemy/api.py
|
||||
def paginate_query(query, model, limit, sort_keys, marker=None,
|
||||
sort_dir=None, sort_dirs=None):
|
||||
"""Returns a query with sorting / pagination criteria added.
|
||||
|
||||
Pagination works by requiring a unique sort_key, specified by sort_keys.
|
||||
(If sort_keys is not unique, then we risk looping through values.)
|
||||
We use the last row in the previous page as the 'marker' for pagination.
|
||||
So we must return values that follow the passed marker in the order.
|
||||
With a single-valued sort_key, this would be easy: sort_key > X.
|
||||
With a compound-values sort_key, (k1, k2, k3) we must do this to repeat
|
||||
the lexicographical ordering:
|
||||
(k1 > X1) or (k1 == X1 && k2 > X2) or (k1 == X1 && k2 == X2 && k3 > X3)
|
||||
|
||||
We also have to cope with different sort_directions.
|
||||
|
||||
Typically, the id of the last row is used as the client-facing pagination
|
||||
marker, then the actual marker object must be fetched from the db and
|
||||
passed in to us as marker.
|
||||
|
||||
:param query: the query object to which we should add paging/sorting
|
||||
:param model: the ORM model class
|
||||
:param limit: maximum number of items to return
|
||||
:param sort_keys: array of attributes by which results should be sorted
|
||||
:param marker: the last item of the previous page; we returns the next
|
||||
results after this value.
|
||||
:param sort_dir: direction in which results should be sorted (asc, desc)
|
||||
:param sort_dirs: per-column array of sort_dirs, corresponding to sort_keys
|
||||
|
||||
:rtype: sqlalchemy.orm.query.Query
|
||||
:return: The query with sorting/pagination added.
|
||||
"""
|
||||
|
||||
if 'id' not in sort_keys:
|
||||
# TODO(justinsb): If this ever gives a false-positive, check
|
||||
# the actual primary key, rather than assuming its id
|
||||
LOG.warn(_('Id not in sort_keys; is sort_keys unique?'))
|
||||
|
||||
assert(not (sort_dir and sort_dirs))
|
||||
|
||||
# Default the sort direction to ascending
|
||||
if sort_dirs is None and sort_dir is None:
|
||||
sort_dir = 'asc'
|
||||
|
||||
# Ensure a per-column sort direction
|
||||
if sort_dirs is None:
|
||||
sort_dirs = [sort_dir for _sort_key in sort_keys]
|
||||
|
||||
assert(len(sort_dirs) == len(sort_keys))
|
||||
|
||||
# Add sorting
|
||||
for current_sort_key, current_sort_dir in zip(sort_keys, sort_dirs):
|
||||
sort_dir_func = {
|
||||
'asc': sqlalchemy.asc,
|
||||
'desc': sqlalchemy.desc,
|
||||
}[current_sort_dir]
|
||||
|
||||
try:
|
||||
sort_key_attr = getattr(model, current_sort_key)
|
||||
except AttributeError:
|
||||
raise exception.InvalidSortKey()
|
||||
query = query.order_by(sort_dir_func(sort_key_attr))
|
||||
|
||||
# Add pagination
|
||||
if marker is not None:
|
||||
marker_values = []
|
||||
for sort_key in sort_keys:
|
||||
v = getattr(marker, sort_key)
|
||||
marker_values.append(v)
|
||||
|
||||
# Build up an array of sort criteria as in the docstring
|
||||
criteria_list = []
|
||||
for i in xrange(0, len(sort_keys)):
|
||||
crit_attrs = []
|
||||
for j in xrange(0, i):
|
||||
model_attr = getattr(model, sort_keys[j])
|
||||
crit_attrs.append((model_attr == marker_values[j]))
|
||||
|
||||
model_attr = getattr(model, sort_keys[i])
|
||||
if sort_dirs[i] == 'desc':
|
||||
crit_attrs.append((model_attr < marker_values[i]))
|
||||
elif sort_dirs[i] == 'asc':
|
||||
crit_attrs.append((model_attr > marker_values[i]))
|
||||
else:
|
||||
raise ValueError(_("Unknown sort direction, "
|
||||
"must be 'desc' or 'asc'"))
|
||||
|
||||
criteria = sqlalchemy.sql.and_(*crit_attrs)
|
||||
criteria_list.append(criteria)
|
||||
|
||||
f = sqlalchemy.sql.or_(*criteria_list)
|
||||
query = query.filter(f)
|
||||
|
||||
if limit is not None:
|
||||
query = query.limit(limit)
|
||||
|
||||
return query
|
||||
@@ -18,6 +18,7 @@ Bare-metal DB testcase for BareMetalInterface
|
||||
"""
|
||||
|
||||
from nova import exception
|
||||
from nova.openstack.common.db.sqlalchemy import session as db_session
|
||||
from nova.tests.baremetal.db import base
|
||||
from nova.virt.baremetal import db
|
||||
|
||||
@@ -27,7 +28,7 @@ class BareMetalInterfaceTestCase(base.BMDBTestCase):
|
||||
def test_unique_address(self):
|
||||
pif1_id = db.bm_interface_create(self.context, 1, '11:11:11:11:11:11',
|
||||
'0x1', 1)
|
||||
self.assertRaises(exception.DBError,
|
||||
self.assertRaises(db_session.DBError,
|
||||
db.bm_interface_create,
|
||||
self.context, 2, '11:11:11:11:11:11', '0x2', 2)
|
||||
# succeed after delete pif1
|
||||
|
||||
@@ -18,6 +18,7 @@ Bare-metal DB testcase for BareMetalPxeIp
|
||||
"""
|
||||
|
||||
from nova import exception
|
||||
from nova.openstack.common.db.sqlalchemy import session as db_session
|
||||
from nova.tests.baremetal.db import base
|
||||
from nova.tests.baremetal.db import utils
|
||||
from nova.virt.baremetal import db
|
||||
@@ -50,14 +51,14 @@ class BareMetalPxeIpTestCase(base.BMDBTestCase):
|
||||
# address duplicates
|
||||
i = utils.new_bm_pxe_ip(address='10.1.1.1',
|
||||
server_address='10.1.1.201')
|
||||
self.assertRaises(exception.DBError,
|
||||
self.assertRaises(db_session.DBError,
|
||||
db.bm_pxe_ip_create_direct,
|
||||
self.context, i)
|
||||
|
||||
# server_address duplicates
|
||||
i = utils.new_bm_pxe_ip(address='10.1.1.3',
|
||||
server_address='10.1.1.101')
|
||||
self.assertRaises(exception.DBError,
|
||||
self.assertRaises(db_session.DBError,
|
||||
db.bm_pxe_ip_create_direct,
|
||||
self.context, i)
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ from testtools import matchers
|
||||
|
||||
from nova import exception
|
||||
from nova.openstack.common import cfg
|
||||
from nova.openstack.common.db.sqlalchemy import session as db_session
|
||||
from nova.tests.baremetal.db import base as bm_db_base
|
||||
from nova.tests.baremetal.db import utils as bm_db_utils
|
||||
from nova.tests.image import fake as fake_image
|
||||
@@ -521,7 +522,7 @@ class PXEPublicMethodsTestCase(BareMetalPXETestCase):
|
||||
AndRaise(exception.NovaException)
|
||||
bm_utils.unlink_without_raise(pxe_path)
|
||||
self.driver._collect_mac_addresses(self.context, self.node).\
|
||||
AndRaise(exception.DBError)
|
||||
AndRaise(db_session.DBError)
|
||||
bm_utils.rmtree_without_raise(
|
||||
os.path.join(CONF.baremetal.tftp_root, 'fake-uuid'))
|
||||
self.mox.ReplayAll()
|
||||
|
||||
@@ -21,8 +21,8 @@ from nova.compute import instance_types
|
||||
from nova import context
|
||||
from nova import db
|
||||
from nova.db.sqlalchemy import models
|
||||
from nova.db.sqlalchemy import session as sql_session
|
||||
from nova import exception
|
||||
from nova.openstack.common.db.sqlalchemy import session as sql_session
|
||||
from nova.openstack.common import log as logging
|
||||
from nova import test
|
||||
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
# Copyright (c) 2012 Rackspace Hosting
|
||||
# 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.
|
||||
|
||||
"""Unit tests for SQLAlchemy specific code."""
|
||||
|
||||
from eventlet import db_pool
|
||||
try:
|
||||
import MySQLdb
|
||||
except ImportError:
|
||||
MySQLdb = None
|
||||
|
||||
from sqlalchemy import Column, MetaData, Table, UniqueConstraint
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy import DateTime, Integer
|
||||
|
||||
from nova import context
|
||||
from nova.db.sqlalchemy import models
|
||||
from nova.db.sqlalchemy import session
|
||||
from nova import exception
|
||||
from nova import test
|
||||
|
||||
|
||||
class DbPoolTestCase(test.TestCase):
|
||||
def setUp(self):
|
||||
super(DbPoolTestCase, self).setUp()
|
||||
self.flags(sql_dbpool_enable=True)
|
||||
self.user_id = 'fake'
|
||||
self.project_id = 'fake'
|
||||
self.context = context.RequestContext(self.user_id, self.project_id)
|
||||
if not MySQLdb:
|
||||
self.skipTest("Unable to test due to lack of MySQLdb")
|
||||
|
||||
def test_db_pool_option(self):
|
||||
self.flags(sql_idle_timeout=11, sql_min_pool_size=21,
|
||||
sql_max_pool_size=42)
|
||||
|
||||
info = {}
|
||||
|
||||
class FakeConnectionPool(db_pool.ConnectionPool):
|
||||
def __init__(self, mod_name, **kwargs):
|
||||
info['module'] = mod_name
|
||||
info['kwargs'] = kwargs
|
||||
super(FakeConnectionPool, self).__init__(mod_name,
|
||||
**kwargs)
|
||||
|
||||
def connect(self, *args, **kwargs):
|
||||
raise test.TestingException()
|
||||
|
||||
self.stubs.Set(db_pool, 'ConnectionPool',
|
||||
FakeConnectionPool)
|
||||
|
||||
sql_connection = 'mysql://user:pass@127.0.0.1/nova'
|
||||
self.assertRaises(test.TestingException, session.create_engine,
|
||||
sql_connection)
|
||||
|
||||
self.assertEqual(info['module'], MySQLdb)
|
||||
self.assertEqual(info['kwargs']['max_idle'], 11)
|
||||
self.assertEqual(info['kwargs']['min_size'], 21)
|
||||
self.assertEqual(info['kwargs']['max_size'], 42)
|
||||
|
||||
|
||||
BASE = declarative_base()
|
||||
_TABLE_NAME = '__tmp__test__tmp__'
|
||||
|
||||
|
||||
class TmpTable(BASE, models.NovaBase):
|
||||
__tablename__ = _TABLE_NAME
|
||||
id = Column(Integer, primary_key=True)
|
||||
foo = Column(Integer)
|
||||
|
||||
|
||||
class SessionErrorWrapperTestCase(test.TestCase):
|
||||
def setUp(self):
|
||||
super(SessionErrorWrapperTestCase, self).setUp()
|
||||
meta = MetaData()
|
||||
meta.bind = session.get_engine()
|
||||
test_table = Table(_TABLE_NAME, meta,
|
||||
Column('id', Integer, primary_key=True,
|
||||
nullable=False),
|
||||
Column('deleted', Integer, default=0),
|
||||
Column('deleted_at', DateTime),
|
||||
Column('updated_at', DateTime),
|
||||
Column('created_at', DateTime),
|
||||
Column('foo', Integer),
|
||||
UniqueConstraint('foo', name='uniq_foo'))
|
||||
test_table.create()
|
||||
|
||||
def tearDown(self):
|
||||
super(SessionErrorWrapperTestCase, self).tearDown()
|
||||
meta = MetaData()
|
||||
meta.bind = session.get_engine()
|
||||
test_table = Table(_TABLE_NAME, meta, autoload=True)
|
||||
test_table.drop()
|
||||
|
||||
def test_flush_wrapper(self):
|
||||
tbl = TmpTable()
|
||||
tbl.update({'foo': 10})
|
||||
tbl.save()
|
||||
|
||||
tbl2 = TmpTable()
|
||||
tbl2.update({'foo': 10})
|
||||
self.assertRaises(exception.DBDuplicateEntry, tbl2.save)
|
||||
|
||||
def test_execute_wrapper(self):
|
||||
_session = session.get_session()
|
||||
with _session.begin():
|
||||
for i in [10, 20]:
|
||||
tbl = TmpTable()
|
||||
tbl.update({'foo': i})
|
||||
tbl.save(session=_session)
|
||||
|
||||
method = _session.query(TmpTable).\
|
||||
filter_by(foo=10).\
|
||||
update
|
||||
self.assertRaises(exception.DBDuplicateEntry,
|
||||
method, {'foo': 20})
|
||||
Reference in New Issue
Block a user