host)
-def volume_data_get_for_project(context, project_id, volume_type_id=None,
- session=None):
+def volume_data_get_for_project(context, project_id):
"""Get (volume_count, gigabytes) for project."""
- return IMPL.volume_data_get_for_project(context,
- project_id,
- volume_type_id,
- session)
+ return IMPL.volume_data_get_for_project(context, project_id)
def finish_volume_migration(context, src_vol_id, dest_vol_id):
return IMPL.snapshot_update(context, snapshot_id, values)
-def snapshot_data_get_for_project(context, project_id, volume_type_id=None,
- session=None):
+def snapshot_data_get_for_project(context, project_id, volume_type_id=None):
"""Get count and gigabytes used for snapshots for specified project."""
return IMPL.snapshot_data_get_for_project(context,
project_id,
- volume_type_id,
- session)
+ volume_type_id)
def snapshot_get_active_by_window(context, begin, end=None, project_id=None):
return query
+def _sync_volumes(context, project_id, session, volume_type_id=None,
+ volume_type_name=None):
+ (volumes, gigs) = _volume_data_get_for_project(
+ context, project_id, volume_type_id=volume_type_id, session=session)
+ key = 'volumes'
+ if volume_type_name:
+ key += '_' + volume_type_name
+ return {key: volumes}
+
+
+def _sync_snapshots(context, project_id, session, volume_type_id=None,
+ volume_type_name=None):
+ (snapshots, gigs) = _snapshot_data_get_for_project(
+ context, project_id, volume_type_id=volume_type_id, session=session)
+ key = 'snapshots'
+ if volume_type_name:
+ key += '_' + volume_type_name
+ return {key: snapshots}
+
+
+def _sync_gigabytes(context, project_id, session, volume_type_id=None,
+ volume_type_name=None):
+ (_junk, vol_gigs) = _volume_data_get_for_project(
+ context, project_id, volume_type_id=volume_type_id, session=session)
+ key = 'gigabytes'
+ if volume_type_name:
+ key += '_' + volume_type_name
+ if CONF.no_snapshot_gb_quota:
+ return {key: vol_gigs}
+ (_junk, snap_gigs) = _snapshot_data_get_for_project(
+ context, project_id, volume_type_id=volume_type_id, session=session)
+ return {key: vol_gigs + snap_gigs}
+
+
+QUOTA_SYNC_FUNCTIONS = {
+ '_sync_volumes': _sync_volumes,
+ '_sync_snapshots': _sync_snapshots,
+ '_sync_gigabytes': _sync_gigabytes,
+}
+
+
###################
# OK, refresh the usage
if refresh:
# Grab the sync routine
- sync = resources[resource].sync
-
- updates = sync(elevated, project_id, session)
+ sync = QUOTA_SYNC_FUNCTIONS[resources[resource].sync]
+ volume_type_id = getattr(resources[resource],
+ 'volume_type_id', None)
+ volume_type_name = getattr(resources[resource],
+ 'volume_type_name', None)
+ updates = sync(elevated, project_id,
+ volume_type_id=volume_type_id,
+ volume_type_name=volume_type_name,
+ session=session)
for res, in_use in updates.items():
# Make sure we have a destination for the usage!
if res not in usages:
@require_admin_context
-def volume_data_get_for_project(context, project_id, volume_type_id=None,
- session=None):
- return _volume_data_get_for_project(context, project_id, volume_type_id,
- session)
+def volume_data_get_for_project(context, project_id, volume_type_id=None):
+ return _volume_data_get_for_project(context, project_id, volume_type_id)
@require_admin_context
@require_context
-def snapshot_data_get_for_project(context, project_id, volume_type_id=None,
- session=None):
- return _snapshot_data_get_for_project(context, project_id, volume_type_id,
- session)
+def snapshot_data_get_for_project(context, project_id, volume_type_id=None):
+ return _snapshot_data_get_for_project(context, project_id, volume_type_id)
@require_context
def get_defaults(self, context, resources):
"""Given a list of resources, retrieve the default quotas.
+
Use the class quotas named `_DEFAULT_QUOTA_NAME` as default quotas,
if it exists.
"""Describe a reservable resource."""
def __init__(self, name, sync, flag=None):
- """
- Initializes a ReservableResource.
+ """Initializes a ReservableResource.
Reservable resources are those resources which directly
correspond to objects in the database, i.e., volumes, gigabytes,
ReservableResource.
:param name: The name of the resource, i.e., "volumes".
- :param sync: A callable which returns a dictionary to
- resynchronize the in_use count for one or more
+ :param sync: A dbapi methods name which returns a dictionary
+ to resynchronize the in_use count for one or more
resources, as described above.
:param flag: The name of the flag or configuration option
which specifies the default value of the quota
"""
def __init__(self, name, count, flag=None):
- """
- Initializes a CountableResource.
+ """Initializes a CountableResource.
Countable resources are those resources which directly
correspond to objects in the database, i.e., volumes, gigabytes,
:param volume_type: The volume type for this resource.
"""
- try:
- method = getattr(self, '_sync_%s' % part_name)
- except AttributeError:
- raise ValueError('Invalid resource: %s' % part_name)
-
self.volume_type_name = volume_type['name']
self.volume_type_id = volume_type['id']
name = "%s_%s" % (part_name, self.volume_type_name)
- super(VolumeTypeResource, self).__init__(name, method)
-
- def _sync_snapshots(self, context, project_id, session):
- """Sync snapshots for this specific volume type."""
- (snapshots, gigs) = db.snapshot_data_get_for_project(
- context,
- project_id,
- volume_type_id=self.volume_type_id,
- session=session)
- return {'snapshots_%s' % self.volume_type_name: snapshots}
-
- def _sync_volumes(self, context, project_id, session):
- """Sync volumes for this specific volume type."""
- (volumes, gigs) = db.volume_data_get_for_project(
- context,
- project_id,
- volume_type_id=self.volume_type_id,
- session=session)
- return {'volumes_%s' % self.volume_type_name: volumes}
-
- def _sync_gigabytes(self, context, project_id, session):
- """Sync gigabytes for this specific volume type."""
- key = 'gigabytes_%s' % self.volume_type_name
- (_junk, vol_gigs) = db.volume_data_get_for_project(
- context,
- project_id,
- volume_type_id=self.volume_type_id,
- session=session)
- if CONF.no_snapshot_gb_quota:
- return {key: vol_gigs}
-
- (_junk, snap_gigs) = db.snapshot_data_get_for_project(
- context,
- project_id,
- volume_type_id=self.volume_type_id,
- session=session)
- return {key: vol_gigs + snap_gigs}
+ super(VolumeTypeResource, self).__init__(name, "_sync_%s" % part_name)
class QuotaEngine(object):
result = {}
# Global quotas.
- argses = [('volumes', _sync_volumes, 'quota_volumes'),
- ('snapshots', _sync_snapshots, 'quota_snapshots'),
- ('gigabytes', _sync_gigabytes, 'quota_gigabytes'), ]
+ argses = [('volumes', '_sync_volumes', 'quota_volumes'),
+ ('snapshots', '_sync_snapshots', 'quota_snapshots'),
+ ('gigabytes', '_sync_gigabytes', 'quota_gigabytes'), ]
for args in argses:
resource = ReservableResource(*args)
result[resource.name] = resource
def register_resources(self, resources):
raise NotImplementedError(_("Cannot register resources"))
-
-def _sync_volumes(context, project_id, session):
- (volumes, gigs) = db.volume_data_get_for_project(context,
- project_id,
- session=session)
- return {'volumes': volumes}
-
-
-def _sync_snapshots(context, project_id, session):
- (snapshots, gigs) = db.snapshot_data_get_for_project(context,
- project_id,
- session=session)
- return {'snapshots': snapshots}
-
-
-def _sync_gigabytes(context, project_id, session):
- (_junk, vol_gigs) = db.volume_data_get_for_project(context,
- project_id,
- session=session)
- if CONF.no_snapshot_gb_quota:
- return {'gigabytes': vol_gigs}
-
- (_junk, snap_gigs) = db.snapshot_data_get_for_project(context,
- project_id,
- session=session)
- return {'gigabytes': vol_gigs + snap_gigs}
-
-
QUOTAS = VolumeTypeQuotaEngine()
quotas = {}
resources = {}
deltas = {}
- for i in range(3):
- resource = 'res%d' % i
- quotas[resource] = db.quota_create(context, project_id, resource, i)
- resources[resource] = ReservableResource(
- resource,
- get_sync(resource, i), 'quota_res_%d' % i)
- deltas[resource] = i
+ for i, resource in enumerate(('volumes', 'gigabytes')):
+ quotas[resource] = db.quota_create(context, project_id,
+ resource, i + 1)
+ resources[resource] = ReservableResource(resource,
+ '_sync_%s' % resource)
+ deltas[resource] = i + 1
return db.quota_reserve(
context, resources, quotas, deltas,
datetime.datetime.utcnow(), datetime.datetime.utcnow(),
def test_reservation_commit(self):
reservations = _quota_reserve(self.ctxt, 'project1')
expected = {'project_id': 'project1',
- 'res0': {'reserved': 0, 'in_use': 0},
- 'res1': {'reserved': 1, 'in_use': 1},
- 'res2': {'reserved': 2, 'in_use': 2}}
+ 'volumes': {'reserved': 1, 'in_use': 0},
+ 'gigabytes': {'reserved': 2, 'in_use': 0},
+ }
self.assertEqual(expected,
db.quota_usage_get_all_by_project(
self.ctxt, 'project1'))
self.ctxt,
reservations[0])
expected = {'project_id': 'project1',
- 'res0': {'reserved': 0, 'in_use': 0},
- 'res1': {'reserved': 0, 'in_use': 2},
- 'res2': {'reserved': 0, 'in_use': 4}}
+ 'volumes': {'reserved': 0, 'in_use': 1},
+ 'gigabytes': {'reserved': 0, 'in_use': 2},
+ }
self.assertEqual(expected,
db.quota_usage_get_all_by_project(
self.ctxt,
def test_reservation_rollback(self):
reservations = _quota_reserve(self.ctxt, 'project1')
expected = {'project_id': 'project1',
- 'res0': {'reserved': 0, 'in_use': 0},
- 'res1': {'reserved': 1, 'in_use': 1},
- 'res2': {'reserved': 2, 'in_use': 2}}
+ 'volumes': {'reserved': 1, 'in_use': 0},
+ 'gigabytes': {'reserved': 2, 'in_use': 0},
+ }
self.assertEqual(expected,
db.quota_usage_get_all_by_project(
self.ctxt,
self.ctxt,
reservations[0])
expected = {'project_id': 'project1',
- 'res0': {'reserved': 0, 'in_use': 0},
- 'res1': {'reserved': 0, 'in_use': 1},
- 'res2': {'reserved': 0, 'in_use': 2}}
+ 'volumes': {'reserved': 0, 'in_use': 0},
+ 'gigabytes': {'reserved': 0, 'in_use': 0},
+ }
self.assertEqual(expected,
db.quota_usage_get_all_by_project(
self.ctxt,
db.reservation_expire(self.ctxt)
expected = {'project_id': 'project1',
- 'res0': {'reserved': 0, 'in_use': 0},
- 'res1': {'reserved': 0, 'in_use': 1},
- 'res2': {'reserved': 0, 'in_use': 2}}
+ 'gigabytes': {'reserved': 0, 'in_use': 0},
+ 'volumes': {'reserved': 0, 'in_use': 0}}
self.assertEqual(expected,
db.quota_usage_get_all_by_project(
self.ctxt,
def test_quota_reserve(self):
reservations = _quota_reserve(self.ctxt, 'project1')
- self.assertEqual(len(reservations), 3)
- res_names = ['res0', 'res1', 'res2']
+ self.assertEqual(len(reservations), 2)
+ res_names = ['gigabytes', 'volumes']
for uuid in reservations:
reservation = db.reservation_get(self.ctxt, uuid)
self.assertTrue(reservation.resource in res_names)
def test_quota_usage_get(self):
reservations = _quota_reserve(self.ctxt, 'p1')
- quota_usage = db.quota_usage_get(self.ctxt, 'p1', 'res0')
- expected = {'resource': 'res0', 'project_id': 'p1',
- 'in_use': 0, 'reserved': 0, 'total': 0}
+ quota_usage = db.quota_usage_get(self.ctxt, 'p1', 'gigabytes')
+ expected = {'resource': 'gigabytes', 'project_id': 'p1',
+ 'in_use': 0, 'reserved': 2, 'total': 2}
for key, value in expected.iteritems():
- self.assertEqual(value, quota_usage[key])
+ self.assertEqual(value, quota_usage[key], key)
def test_quota_usage_get_all_by_project(self):
reservations = _quota_reserve(self.ctxt, 'p1')
expected = {'project_id': 'p1',
- 'res0': {'in_use': 0, 'reserved': 0},
- 'res1': {'in_use': 1, 'reserved': 1},
- 'res2': {'in_use': 2, 'reserved': 2}}
+ 'volumes': {'in_use': 0, 'reserved': 1},
+ 'gigabytes': {'in_use': 0, 'reserved': 2}}
self.assertEqual(expected, db.quota_usage_get_all_by_project(
self.ctxt, 'p1'))
test_resource2=resources[1],
test_resource3=resources[2], ))
- def test_sync_predeclared(self):
- quota_obj = quota.QuotaEngine()
-
- def spam(*args, **kwargs):
- pass
-
- resource = quota.ReservableResource('test_resource', spam)
- quota_obj.register_resource(resource)
-
- self.assertEqual(resource.sync, spam)
-
- def test_sync_multi(self):
- quota_obj = quota.QuotaEngine()
-
- def spam(*args, **kwargs):
- pass
-
- resources = [
- quota.ReservableResource('test_resource1', spam),
- quota.ReservableResource('test_resource2', spam),
- quota.ReservableResource('test_resource3', spam),
- quota.ReservableResource('test_resource4', spam), ]
- quota_obj.register_resources(resources[:2])
-
- self.assertEqual(resources[0].sync, spam)
- self.assertEqual(resources[1].sync, spam)
- self.assertEqual(resources[2].sync, spam)
- self.assertEqual(resources[3].sync, spam)
-
def test_get_by_project(self):
context = FakeContext('test_project', 'test_class')
driver = FakeDriver(
self.sync_called = set()
def make_sync(res_name):
- def sync(context, project_id, session):
+ def fake_sync(context, project_id, volume_type_id=None,
+ volume_type_name=None, session=None):
self.sync_called.add(res_name)
if res_name in self.usages:
if self.usages[res_name].in_use < 0:
else:
return {res_name: self.usages[res_name].in_use - 1}
return {res_name: 0}
- return sync
+ return fake_sync
self.resources = {}
+ QUOTA_SYNC_FUNCTIONS = {}
for res_name in ('volumes', 'gigabytes'):
- res = quota.ReservableResource(res_name, make_sync(res_name))
+ res = quota.ReservableResource(res_name, '_sync_%s' % res_name)
+ QUOTA_SYNC_FUNCTIONS['_sync_%s' % res_name] = make_sync(res_name)
self.resources[res_name] = res
+ self.stubs.Set(sqa_api, 'QUOTA_SYNC_FUNCTIONS', QUOTA_SYNC_FUNCTIONS)
self.expire = timeutils.utcnow() + datetime.timedelta(seconds=3600)
self.usages = {}