from oslo.config import cfg
+from cinder import context
from cinder import db
from cinder import exception
from cinder.openstack.common import importutils
database.
"""
- def get_by_project(self, context, project_id, resource):
+ def get_by_project(self, context, project_id, resource_name):
"""Get a specific quota by project."""
- return db.quota_get(context, project_id, resource)
+ return db.quota_get(context, project_id, resource_name)
- def get_by_class(self, context, quota_class, resource):
+ def get_by_class(self, context, quota_class, resource_name):
"""Get a specific quota by quota class."""
- return db.quota_class_get(context, quota_class, resource)
+ return db.quota_class_get(context, quota_class, resource_name)
+
+ def get_default(self, context, resource):
+ """Get a specific default quota for a resource."""
+
+ default_quotas = db.quota_class_get_default(context)
+ return default_quotas.get(resource.name, resource.default)
def get_defaults(self, context, resources):
"""Given a list of resources, retrieve the default quotas.
"""
quotas = {}
+ default_quotas = {}
class_quotas = db.quota_class_get_all_by_name(context, quota_class)
+ if defaults:
+ default_quotas = db.quota_class_get_default(context)
for resource in resources.values():
- if defaults or resource.name in class_quotas:
- quotas[resource.name] = class_quotas.get(resource.name,
- resource.default)
+ if resource.name in class_quotas:
+ quotas[resource.name] = class_quotas[resource.name]
+ continue
+
+ if defaults:
+ quotas[resource.name] = default_quotas.get(resource.name,
+ resource.default)
return quotas
pass
# OK, return the default
- return self.default
+ return driver.get_default(context, self)
@property
def default(self):
self.count = count
+class VolumeTypeResource(ReservableResource):
+ """ReservableResource for a specific volume type."""
+
+ def __init__(self, part_name, volume_type):
+ """
+ Initializes a VolumeTypeResource.
+
+ :param part_name: The kind of resource, i.e., "volumes".
+ :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}
+
+
class QuotaEngine(object):
"""Represent the set of recognized quotas."""
self._driver = quota_driver_class
def __contains__(self, resource):
- return resource in self._resources
+ return resource in self.resources
def register_resource(self, resource):
"""Register a resource."""
for resource in resources:
self.register_resource(resource)
- def get_by_project(self, context, project_id, resource):
+ def get_by_project(self, context, project_id, resource_name):
"""Get a specific quota by project."""
- return self._driver.get_by_project(context, project_id, resource)
+ return self._driver.get_by_project(context, project_id, resource_name)
- def get_by_class(self, context, quota_class, resource):
+ def get_by_class(self, context, quota_class, resource_name):
"""Get a specific quota by quota class."""
- return self._driver.get_by_class(context, quota_class, resource)
+ return self._driver.get_by_class(context, quota_class, resource_name)
+
+ def get_default(self, context, resource):
+ """Get a specific default quota for a resource."""
+
+ return self._driver.get_default(context, resource)
def get_defaults(self, context):
"""Retrieve the default quotas.
:param context: The request context, for access checks.
"""
- return self._driver.get_defaults(context, self._resources)
+ return self._driver.get_defaults(context, self.resources)
def get_class_quotas(self, context, quota_class, defaults=True):
"""Retrieve the quotas for the given quota class.
resource.
"""
- return self._driver.get_class_quotas(context, self._resources,
+ return self._driver.get_class_quotas(context, self.resources,
quota_class, defaults=defaults)
def get_project_quotas(self, context, project_id, quota_class=None,
will also be returned.
"""
- return self._driver.get_project_quotas(context, self._resources,
+ return self._driver.get_project_quotas(context, self.resources,
project_id,
quota_class=quota_class,
defaults=defaults,
"""
# Get the resource
- res = self._resources.get(resource)
+ res = self.resources.get(resource)
if not res or not hasattr(res, 'count'):
raise exception.QuotaResourceUnknown(unknown=[resource])
common user's tenant.
"""
- return self._driver.limit_check(context, self._resources, values,
+ return self._driver.limit_check(context, self.resources, values,
project_id=project_id)
def reserve(self, context, expire=None, project_id=None, **deltas):
common user's tenant.
"""
- reservations = self._driver.reserve(context, self._resources, deltas,
+ reservations = self._driver.reserve(context, self.resources, deltas,
expire=expire,
project_id=project_id)
self._driver.expire(context)
+ def add_volume_type_opts(self, context, opts, volume_type_id):
+ """Add volume type resource options.
+
+ Adds elements to the opts hash for volume type quotas.
+ If a resource is being reserved ('gigabytes', etc) and the volume
+ type is set up for its own quotas, these reservations are copied
+ into keys for 'gigabytes_<volume type name>', etc.
+
+ :param context: The request context, for access checks.
+ :param opts: The reservations options hash.
+ :param volume_type_id: The volume type id for this reservation.
+ """
+ if not volume_type_id:
+ return
+ volume_type = db.volume_type_get(context, volume_type_id)
+ for quota in ('volumes', 'gigabytes', 'snapshots'):
+ if quota in opts:
+ vtype_quota = "%s_%s" % (quota, volume_type['name'])
+ opts[vtype_quota] = opts[quota]
+
+ @property
+ def resource_names(self):
+ return sorted(self.resources.keys())
+
+ @property
+ def resources(self):
+ return self._resources
+
+
+class VolumeTypeQuotaEngine(QuotaEngine):
+ """Represent the set of all quotas."""
+
@property
def resources(self):
- return sorted(self._resources.keys())
+ """Fetches all possible quota resources."""
+
+ result = {}
+ # Global quotas.
+ 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
+
+ # Volume type quotas.
+ volume_types = db.volume_type_get_all(context.get_admin_context())
+ for volume_type in volume_types.values():
+ for part_name in ('volumes', 'gigabytes', 'snapshots'):
+ resource = VolumeTypeResource(part_name, volume_type)
+ result[resource.name] = resource
+ return result
+
+ def register_resource(self, resource):
+ raise NotImplementedError(_("Cannot register resource"))
+
+ def register_resources(self, resources):
+ raise NotImplementedError(_("Cannot register resources"))
def _sync_volumes(context, project_id, session):
return {'gigabytes': vol_gigs + snap_gigs}
-QUOTAS = QuotaEngine()
-
-
-resources = [
- ReservableResource('volumes', _sync_volumes, 'quota_volumes'),
- ReservableResource('snapshots', _sync_snapshots, 'quota_snapshots'),
- ReservableResource('gigabytes', _sync_gigabytes, 'quota_gigabytes'), ]
-
-
-QUOTAS.register_resources(resources)
+QUOTAS = VolumeTypeQuotaEngine()
def setUp(self):
super(QuotaIntegrationTestCase, self).setUp()
+ self.volume_type_name = CONF.default_volume_type
+ self.volume_type = db.volume_type_create(
+ context.get_admin_context(),
+ dict(name=self.volume_type_name))
+
self.flags(quota_volumes=2,
quota_snapshots=2,
quota_gigabytes=20)
- # Apparently needed by the RPC tests...
- #self.network = self.start_service('network')
-
self.user_id = 'admin'
self.project_id = 'admin'
self.context = context.RequestContext(self.user_id,
self.stubs.Set(rpc, 'call', rpc_call_wrapper)
def tearDown(self):
+ db.volume_type_destroy(context.get_admin_context(),
+ self.volume_type['id'])
super(QuotaIntegrationTestCase, self).tearDown()
cinder.tests.image.fake.FakeImageService_reset()
- def _create_volume(self, size=10):
+ def _create_volume(self, size=1):
"""Create a test volume."""
vol = {}
vol['user_id'] = self.user_id
vol['project_id'] = self.project_id
vol['size'] = size
vol['status'] = 'available'
+ vol['volume_type_id'] = self.volume_type['id']
return db.volume_create(self.context, vol)
def _create_snapshot(self, volume):
for i in range(CONF.quota_volumes):
vol_ref = self._create_volume()
volume_ids.append(vol_ref['id'])
- self.assertRaises(exception.QuotaError,
+ self.assertRaises(exception.VolumeLimitExceeded,
volume.API().create,
- self.context, 10, '', '', None)
+ self.context, 1, '', '',
+ volume_type=self.volume_type)
for volume_id in volume_ids:
db.volume_destroy(self.context, volume_id)
+ def test_too_many_volumes_of_type(self):
+ resource = 'volumes_%s' % self.volume_type_name
+ db.quota_class_create(self.context, 'default', resource, 1)
+ flag_args = {
+ 'quota_volumes': 2000,
+ 'quota_gigabytes': 2000
+ }
+ self.flags(**flag_args)
+ vol_ref = self._create_volume()
+ self.assertRaises(exception.VolumeLimitExceeded,
+ volume.API().create,
+ self.context, 1, '', '',
+ volume_type=self.volume_type)
+ db.volume_destroy(self.context, vol_ref['id'])
+
+ def test_too_many_snapshots_of_type(self):
+ resource = 'snapshots_%s' % self.volume_type_name
+ db.quota_class_create(self.context, 'default', resource, 1)
+ flag_args = {
+ 'quota_volumes': 2000,
+ 'quota_gigabytes': 2000,
+ }
+ self.flags(**flag_args)
+ vol_ref = self._create_volume()
+ snap_ref = self._create_snapshot(vol_ref)
+ self.assertRaises(exception.SnapshotLimitExceeded,
+ volume.API().create_snapshot,
+ self.context, vol_ref, '', '')
+ db.snapshot_destroy(self.context, snap_ref['id'])
+ db.volume_destroy(self.context, vol_ref['id'])
+
def test_too_many_gigabytes(self):
volume_ids = []
vol_ref = self._create_volume(size=20)
volume_ids.append(vol_ref['id'])
- self.assertRaises(exception.QuotaError,
+ self.assertRaises(exception.VolumeSizeExceedsAvailableQuota,
volume.API().create,
- self.context, 10, '', '', None)
+ self.context, 1, '', '',
+ volume_type=self.volume_type)
for volume_id in volume_ids:
db.volume_destroy(self.context, volume_id)
self.assertEqual(reservations.get('gigabytes'), None)
# Make sure the snapshot volume_size isn't included in usage.
- vol_type = db.volume_type_create(self.context,
- dict(name=CONF.default_volume_type))
vol_ref2 = volume.API().create(self.context, 10, '', '')
usages = db.quota_usage_get_all_by_project(self.context,
self.project_id)
db.snapshot_destroy(self.context, snap_ref2['id'])
db.volume_destroy(self.context, vol_ref['id'])
db.volume_destroy(self.context, vol_ref2['id'])
- db.volume_type_destroy(self.context, vol_type['id'])
+
+ def test_too_many_gigabytes_of_type(self):
+ resource = 'gigabytes_%s' % self.volume_type_name
+ db.quota_class_create(self.context, 'default', resource, 10)
+ flag_args = {
+ 'quota_volumes': 2000,
+ 'quota_gigabytes': 2000,
+ }
+ self.flags(**flag_args)
+ vol_ref = self._create_volume(size=10)
+ self.assertRaises(exception.VolumeSizeExceedsAvailableQuota,
+ volume.API().create,
+ self.context, 1, '', '',
+ volume_type=self.volume_type)
+ db.volume_destroy(self.context, vol_ref['id'])
class FakeContext(object):
except KeyError:
raise exception.QuotaClassNotFound(class_name=quota_class)
+ def get_default(self, context, resource):
+ self.called.append(('get_default', context, resource))
+ return resource.default
+
def get_defaults(self, context, resources):
self.called.append(('get_defaults', context, resources))
return resources
self.assertEqual(quota_value, 20)
+class VolumeTypeResourceTestCase(test.TestCase):
+ def test_name_and_flag(self):
+ volume_type_name = 'foo'
+ volume = {'name': volume_type_name, 'id': 'myid'}
+ resource = quota.VolumeTypeResource('volumes', volume)
+
+ self.assertEqual(resource.name, 'volumes_%s' % volume_type_name)
+ self.assertEqual(resource.flag, None)
+ self.assertEqual(resource.default, -1)
+
+
class QuotaEngineTestCase(test.TestCase):
def test_init(self):
quota_obj = quota.QuotaEngine()
- self.assertEqual(quota_obj._resources, {})
+ self.assertEqual(quota_obj.resources, {})
self.assertTrue(isinstance(quota_obj._driver, quota.DbQuotaDriver))
def test_init_override_string(self):
quota_obj = quota.QuotaEngine(
quota_driver_class='cinder.tests.test_quota.FakeDriver')
- self.assertEqual(quota_obj._resources, {})
+ self.assertEqual(quota_obj.resources, {})
self.assertTrue(isinstance(quota_obj._driver, FakeDriver))
def test_init_override_obj(self):
quota_obj = quota.QuotaEngine(quota_driver_class=FakeDriver)
- self.assertEqual(quota_obj._resources, {})
+ self.assertEqual(quota_obj.resources, {})
self.assertEqual(quota_obj._driver, FakeDriver)
def test_register_resource(self):
resource = quota.AbsoluteResource('test_resource')
quota_obj.register_resource(resource)
- self.assertEqual(quota_obj._resources, dict(test_resource=resource))
+ self.assertEqual(quota_obj.resources, dict(test_resource=resource))
def test_register_resources(self):
quota_obj = quota.QuotaEngine()
quota.AbsoluteResource('test_resource3'), ]
quota_obj.register_resources(resources)
- self.assertEqual(quota_obj._resources,
+ self.assertEqual(quota_obj.resources,
dict(test_resource1=resources[0],
test_resource2=resources[1],
test_resource3=resources[2], ))
self.assertEqual(driver.called, [('get_defaults',
context,
- quota_obj._resources), ])
- self.assertEqual(result, quota_obj._resources)
+ quota_obj.resources), ])
+ self.assertEqual(result, quota_obj.resources)
def test_get_class_quotas(self):
context = FakeContext(None, None)
self.assertEqual(driver.called, [
('get_class_quotas',
context,
- quota_obj._resources,
+ quota_obj.resources,
'test_class', True),
('get_class_quotas',
- context, quota_obj._resources,
+ context, quota_obj.resources,
'test_class', False), ])
- self.assertEqual(result1, quota_obj._resources)
- self.assertEqual(result2, quota_obj._resources)
+ self.assertEqual(result1, quota_obj.resources)
+ self.assertEqual(result2, quota_obj.resources)
def test_get_project_quotas(self):
context = FakeContext(None, None)
self.assertEqual(driver.called, [
('get_project_quotas',
context,
- quota_obj._resources,
+ quota_obj.resources,
'test_project',
None,
True,
True),
('get_project_quotas',
context,
- quota_obj._resources,
+ quota_obj.resources,
'test_project',
'test_class',
False,
False), ])
- self.assertEqual(result1, quota_obj._resources)
- self.assertEqual(result2, quota_obj._resources)
+ self.assertEqual(result1, quota_obj.resources)
+ self.assertEqual(result2, quota_obj.resources)
def test_count_no_resource(self):
context = FakeContext(None, None)
self.assertEqual(driver.called, [
('limit_check',
context,
- quota_obj._resources,
+ quota_obj.resources,
dict(
test_resource1=4,
test_resource2=3,
self.assertEqual(driver.called, [
('reserve',
context,
- quota_obj._resources,
+ quota_obj.resources,
dict(
test_resource1=4,
test_resource2=3,
None),
('reserve',
context,
- quota_obj._resources,
+ quota_obj.resources,
dict(
test_resource1=1,
test_resource2=2,
None),
('reserve',
context,
- quota_obj._resources,
+ quota_obj.resources,
dict(
test_resource1=1,
test_resource2=2,
self.assertEqual(driver.called, [('expire', context), ])
- def test_resources(self):
+ def test_resource_names(self):
quota_obj = self._make_quota_obj(None)
- self.assertEqual(quota_obj.resources,
+ self.assertEqual(quota_obj.resource_names,
['test_resource1', 'test_resource2',
'test_resource3', 'test_resource4'])
+class VolumeTypeQuotaEngineTestCase(test.TestCase):
+ def test_default_resources(self):
+ engine = quota.VolumeTypeQuotaEngine()
+ self.assertEqual(engine.resource_names,
+ ['gigabytes', 'snapshots', 'volumes'])
+
+ def test_volume_type_resources(self):
+ ctx = context.RequestContext('admin', 'admin', is_admin=True)
+ vtype = db.volume_type_create(ctx, {'name': 'type1'})
+ vtype2 = db.volume_type_create(ctx, {'name': 'type_2'})
+ engine = quota.VolumeTypeQuotaEngine()
+ self.assertEqual(engine.resource_names,
+ ['gigabytes', 'gigabytes_type1', 'gigabytes_type_2',
+ 'snapshots', 'snapshots_type1', 'snapshots_type_2',
+ 'volumes', 'volumes_type1', 'volumes_type_2'])
+ db.volume_type_destroy(ctx, vtype['id'])
+ db.volume_type_destroy(ctx, vtype2['id'])
+
+
class DbQuotaDriverTestCase(test.TestCase):
def setUp(self):
super(DbQuotaDriverTestCase, self).setUp()
def test_get_defaults(self):
# Use our pre-defined resources
self._stub_quota_class_get_default()
- result = self.driver.get_defaults(None, quota.QUOTAS._resources)
+ result = self.driver.get_defaults(None, quota.QUOTAS.resources)
self.assertEqual(
result,
def test_get_class_quotas(self):
self._stub_quota_class_get_all_by_name()
- result = self.driver.get_class_quotas(None, quota.QUOTAS._resources,
+ result = self.driver.get_class_quotas(None, quota.QUOTAS.resources,
'test_class')
self.assertEqual(self.calls, ['quota_class_get_all_by_name'])
def test_get_class_quotas_no_defaults(self):
self._stub_quota_class_get_all_by_name()
- result = self.driver.get_class_quotas(None, quota.QUOTAS._resources,
+ result = self.driver.get_class_quotas(None, quota.QUOTAS.resources,
'test_class', False)
self.assertEqual(self.calls, ['quota_class_get_all_by_name'])
self._stub_get_by_project()
result = self.driver.get_project_quotas(
FakeContext('test_project', 'test_class'),
- quota.QUOTAS._resources, 'test_project')
+ quota.QUOTAS.resources, 'test_project')
self.assertEqual(self.calls, ['quota_get_all_by_project',
'quota_usage_get_all_by_project',
self._stub_get_by_project()
result = self.driver.get_project_quotas(
FakeContext('other_project', 'other_class'),
- quota.QUOTAS._resources, 'test_project')
+ quota.QUOTAS.resources, 'test_project')
self.assertEqual(self.calls, ['quota_get_all_by_project',
'quota_usage_get_all_by_project',
self._stub_get_by_project()
result = self.driver.get_project_quotas(
FakeContext('other_project', 'other_class'),
- quota.QUOTAS._resources, 'test_project', quota_class='test_class')
+ quota.QUOTAS.resources, 'test_project', quota_class='test_class')
self.assertEqual(self.calls, ['quota_get_all_by_project',
'quota_usage_get_all_by_project',
self._stub_get_by_project()
result = self.driver.get_project_quotas(
FakeContext('test_project', 'test_class'),
- quota.QUOTAS._resources, 'test_project', defaults=False)
+ quota.QUOTAS.resources, 'test_project', defaults=False)
self.assertEqual(self.calls, ['quota_get_all_by_project',
'quota_usage_get_all_by_project',
self._stub_get_by_project()
result = self.driver.get_project_quotas(
FakeContext('test_project', 'test_class'),
- quota.QUOTAS._resources, 'test_project', usages=False)
+ quota.QUOTAS.resources, 'test_project', usages=False)
self.assertEqual(self.calls, ['quota_get_all_by_project',
'quota_class_get_all_by_name',
self._stub_get_project_quotas()
self.assertRaises(exception.QuotaResourceUnknown,
self.driver._get_quotas,
- None, quota.QUOTAS._resources,
+ None, quota.QUOTAS.resources,
['unknown'], True)
self.assertEqual(self.calls, [])
self._stub_get_project_quotas()
self.assertRaises(exception.QuotaResourceUnknown,
self.driver._get_quotas,
- None, quota.QUOTAS._resources,
+ None, quota.QUOTAS.resources,
['unknown'], False)
self.assertEqual(self.calls, [])
self._stub_get_project_quotas()
self.assertRaises(exception.QuotaResourceUnknown,
self.driver._get_quotas,
- None, quota.QUOTAS._resources,
+ None, quota.QUOTAS.resources,
['metadata_items'], True)
self.assertEqual(self.calls, [])
self._stub_get_project_quotas()
self.assertRaises(exception.QuotaResourceUnknown,
self.driver._get_quotas,
- None, quota.QUOTAS._resources,
+ None, quota.QUOTAS.resources,
['volumes'], False)
self.assertEqual(self.calls, [])
self._stub_get_project_quotas()
result = self.driver._get_quotas(FakeContext('test_project',
'test_class'),
- quota.QUOTAS._resources,
+ quota.QUOTAS.resources,
['volumes', 'gigabytes'],
True)
self.assertRaises(exception.InvalidReservationExpiration,
self.driver.reserve,
FakeContext('test_project', 'test_class'),
- quota.QUOTAS._resources,
+ quota.QUOTAS.resources,
dict(volumes=2), expire='invalid')
self.assertEqual(self.calls, [])
self._stub_get_project_quotas()
self._stub_quota_reserve()
result = self.driver.reserve(FakeContext('test_project', 'test_class'),
- quota.QUOTAS._resources,
+ quota.QUOTAS.resources,
dict(volumes=2))
expire = timeutils.utcnow() + datetime.timedelta(seconds=86400)
self._stub_get_project_quotas()
self._stub_quota_reserve()
result = self.driver.reserve(FakeContext('test_project', 'test_class'),
- quota.QUOTAS._resources,
+ quota.QUOTAS.resources,
dict(volumes=2), expire=3600)
expire = timeutils.utcnow() + datetime.timedelta(seconds=3600)
self._stub_quota_reserve()
expire_delta = datetime.timedelta(seconds=60)
result = self.driver.reserve(FakeContext('test_project', 'test_class'),
- quota.QUOTAS._resources,
+ quota.QUOTAS.resources,
dict(volumes=2), expire=expire_delta)
expire = timeutils.utcnow() + expire_delta
self._stub_quota_reserve()
expire = timeutils.utcnow() + datetime.timedelta(seconds=120)
result = self.driver.reserve(FakeContext('test_project', 'test_class'),
- quota.QUOTAS._resources,
+ quota.QUOTAS.resources,
dict(volumes=2), expire=expire)
self.assertEqual(self.calls, ['get_project_quotas',
self.flags(until_refresh=500)
expire = timeutils.utcnow() + datetime.timedelta(seconds=120)
result = self.driver.reserve(FakeContext('test_project', 'test_class'),
- quota.QUOTAS._resources,
+ quota.QUOTAS.resources,
dict(volumes=2), expire=expire)
self.assertEqual(self.calls, ['get_project_quotas',
self.flags(max_age=86400)
expire = timeutils.utcnow() + datetime.timedelta(seconds=120)
result = self.driver.reserve(FakeContext('test_project', 'test_class'),
- quota.QUOTAS._resources,
+ quota.QUOTAS.resources,
dict(volumes=2), expire=expire)
self.assertEqual(self.calls, ['get_project_quotas',
msg = _('Image minDisk size is larger than the volume size.')
raise exception.InvalidInput(reason=msg)
+ if not volume_type and not source_volume:
+ volume_type = volume_types.get_default_volume_type()
+
+ if not volume_type and source_volume:
+ volume_type_id = source_volume['volume_type_id']
+ else:
+ volume_type_id = volume_type.get('id')
+
try:
- reservations = QUOTAS.reserve(context, volumes=1, gigabytes=size)
+ reserve_opts = {'volumes': 1, 'gigabytes': size}
+ QUOTAS.add_volume_type_opts(context, reserve_opts, volume_type_id)
+ reservations = QUOTAS.reserve(context, **reserve_opts)
except exception.OverQuota as e:
overs = e.kwargs['overs']
usages = e.kwargs['usages']
def _consumed(name):
return (usages[name]['reserved'] + usages[name]['in_use'])
- if 'gigabytes' in overs:
- msg = _("Quota exceeded for %(s_pid)s, tried to create "
- "%(s_size)sG volume (%(d_consumed)dG of %(d_quota)dG "
- "already consumed)")
- LOG.warn(msg % {'s_pid': context.project_id,
- 's_size': size,
- 'd_consumed': _consumed('gigabytes'),
- 'd_quota': quotas['gigabytes']})
- raise exception.VolumeSizeExceedsAvailableQuota()
- elif 'volumes' in overs:
- msg = _("Quota exceeded for %(s_pid)s, tried to create "
- "volume (%(d_consumed)d volumes "
- "already consumed)")
- LOG.warn(msg % {'s_pid': context.project_id,
- 'd_consumed': _consumed('volumes')})
- raise exception.VolumeLimitExceeded(allowed=quotas['volumes'])
+ for over in overs:
+ if 'gigabytes' in over:
+ msg = _("Quota exceeded for %(s_pid)s, tried to create "
+ "%(s_size)sG volume (%(d_consumed)dG of "
+ "%(d_quota)dG already consumed)")
+ LOG.warn(msg % {'s_pid': context.project_id,
+ 's_size': size,
+ 'd_consumed': _consumed(over),
+ 'd_quota': quotas[over]})
+ raise exception.VolumeSizeExceedsAvailableQuota()
+ elif 'volumes' in over:
+ msg = _("Quota exceeded for %(s_pid)s, tried to create "
+ "volume (%(d_consumed)d volumes"
+ "already consumed)")
+ LOG.warn(msg % {'s_pid': context.project_id,
+ 'd_consumed': _consumed(over)})
+ raise exception.VolumeLimitExceeded(allowed=quotas[over])
if availability_zone is None:
availability_zone = CONF.storage_availability_zone
else:
self._check_availabilty_zone(availability_zone)
- if not volume_type and not source_volume:
- volume_type = volume_types.get_default_volume_type()
-
- if not volume_type and source_volume:
- volume_type_id = source_volume['volume_type_id']
- else:
- volume_type_id = volume_type.get('id')
-
self._check_metadata_properties(context, metadata)
options = {'size': size,
'user_id': context.user_id,
# NOTE(vish): scheduling failed, so delete it
# Note(zhiteng): update volume quota reservation
try:
+ reserve_opts = {'volumes': -1, 'gigabytes': -volume['size']}
+ QUOTAS.add_volume_type_opts(context,
+ reserve_opts,
+ volume['volume_type_id'])
reservations = QUOTAS.reserve(context,
project_id=project_id,
- volumes=-1,
- gigabytes=-volume['size'])
+ **reserve_opts)
except Exception:
reservations = None
LOG.exception(_("Failed to update quota for deleting volume"))
try:
if CONF.no_snapshot_gb_quota:
- reservations = QUOTAS.reserve(context, snapshots=1)
+ reserve_opts = {'snapshots': 1}
else:
- reservations = QUOTAS.reserve(context, snapshots=1,
- gigabytes=volume['size'])
+ reserve_opts = {'snapshots': 1, 'gigabytes': volume['size']}
+ QUOTAS.add_volume_type_opts(context,
+ reserve_opts,
+ volume.get('volume_type_id'))
+ reservations = QUOTAS.reserve(context, **reserve_opts)
except exception.OverQuota as e:
overs = e.kwargs['overs']
usages = e.kwargs['usages']
def _consumed(name):
return (usages[name]['reserved'] + usages[name]['in_use'])
- if 'gigabytes' in overs:
- msg = _("Quota exceeded for %(s_pid)s, tried to create "
- "%(s_size)sG snapshot (%(d_consumed)dG of "
- "%(d_quota)dG already consumed)")
- LOG.warn(msg % {'s_pid': context.project_id,
- 's_size': volume['size'],
- 'd_consumed': _consumed('gigabytes'),
- 'd_quota': quotas['gigabytes']})
- raise exception.VolumeSizeExceedsAvailableQuota()
- elif 'snapshots' in overs:
- msg = _("Quota exceeded for %(s_pid)s, tried to create "
- "snapshot (%(d_consumed)d snapshots "
- "already consumed)")
-
- LOG.warn(msg % {'s_pid': context.project_id,
- 'd_consumed': _consumed('snapshots')})
- raise exception.SnapshotLimitExceeded(
- allowed=quotas['snapshots'])
+ for over in overs:
+ if 'gigabytes' in over:
+ msg = _("Quota exceeded for %(s_pid)s, tried to create "
+ "%(s_size)sG snapshot (%(d_consumed)dG of "
+ "%(d_quota)dG already consumed)")
+ LOG.warn(msg % {'s_pid': context.project_id,
+ 's_size': volume['size'],
+ 'd_consumed': _consumed(over),
+ 'd_quota': quotas[over]})
+ raise exception.VolumeSizeExceedsAvailableQuota()
+ elif 'snapshots' in over:
+ msg = _("Quota exceeded for %(s_pid)s, tried to create "
+ "snapshot (%(d_consumed)d snapshots "
+ "already consumed)")
+
+ LOG.warn(msg % {'s_pid': context.project_id,
+ 'd_consumed': _consumed(over)})
+ raise exception.SnapshotLimitExceeded(
+ allowed=quotas[over])
self._check_metadata_properties(context, metadata)
options = {'volume_id': volume['id'],