Merge "Handle quota exceed exception"
This commit is contained in:
commit
cb41b2713e
|
@ -33,11 +33,12 @@ from cinder.backup import rpcapi as backup_rpcapi
|
|||
from cinder import context
|
||||
from cinder.db import base
|
||||
from cinder import exception
|
||||
from cinder.i18n import _, _LI, _LW
|
||||
from cinder.i18n import _, _LI
|
||||
from cinder import objects
|
||||
from cinder.objects import fields
|
||||
import cinder.policy
|
||||
from cinder import quota
|
||||
from cinder import quota_utils
|
||||
from cinder import utils
|
||||
import cinder.volume
|
||||
from cinder.volume import utils as volume_utils
|
||||
|
@ -279,37 +280,10 @@ class API(base.Base):
|
|||
'backup_gigabytes': volume['size']}
|
||||
reservations = QUOTAS.reserve(context, **reserve_opts)
|
||||
except exception.OverQuota as e:
|
||||
overs = e.kwargs['overs']
|
||||
usages = e.kwargs['usages']
|
||||
quotas = e.kwargs['quotas']
|
||||
|
||||
def _consumed(resource_name):
|
||||
return (usages[resource_name]['reserved'] +
|
||||
usages[resource_name]['in_use'])
|
||||
|
||||
for over in overs:
|
||||
if 'gigabytes' in over:
|
||||
msg = _LW("Quota exceeded for %(s_pid)s, tried to create "
|
||||
"%(s_size)sG backup (%(d_consumed)dG of "
|
||||
"%(d_quota)dG already consumed)")
|
||||
LOG.warning(msg, {'s_pid': context.project_id,
|
||||
's_size': volume['size'],
|
||||
'd_consumed': _consumed(over),
|
||||
'd_quota': quotas[over]})
|
||||
raise exception.VolumeBackupSizeExceedsAvailableQuota(
|
||||
requested=volume['size'],
|
||||
consumed=_consumed('backup_gigabytes'),
|
||||
quota=quotas['backup_gigabytes'])
|
||||
elif 'backups' in over:
|
||||
msg = _LW("Quota exceeded for %(s_pid)s, tried to create "
|
||||
"backups (%(d_consumed)d backups "
|
||||
"already consumed)")
|
||||
|
||||
LOG.warning(msg, {'s_pid': context.project_id,
|
||||
'd_consumed': _consumed(over)})
|
||||
raise exception.BackupLimitExceeded(
|
||||
allowed=quotas[over])
|
||||
|
||||
quota_utils.process_reserve_over_quota(
|
||||
context, e,
|
||||
resource='backups',
|
||||
size=volume.size)
|
||||
# Find the latest backup and use it as the parent backup to do an
|
||||
# incremental backup.
|
||||
latest_backup = None
|
||||
|
|
|
@ -540,6 +540,10 @@ class SnapshotLimitExceeded(QuotaError):
|
|||
message = _("Maximum number of snapshots allowed (%(allowed)d) exceeded")
|
||||
|
||||
|
||||
class UnexpectedOverQuota(QuotaError):
|
||||
message = _("Unexpected over quota on %(name)s.")
|
||||
|
||||
|
||||
class BackupLimitExceeded(QuotaError):
|
||||
message = _("Maximum number of backups allowed (%(allowed)d) exceeded")
|
||||
|
||||
|
|
|
@ -70,37 +70,9 @@ def get_volume_type_reservation(ctxt, volume, type_id,
|
|||
project_id=project_id,
|
||||
**reserve_opts)
|
||||
except exception.OverQuota as e:
|
||||
overs = e.kwargs['overs']
|
||||
usages = e.kwargs['usages']
|
||||
quotas = e.kwargs['quotas']
|
||||
|
||||
def _consumed(name):
|
||||
return (usages[name]['reserved'] + usages[name]['in_use'])
|
||||
|
||||
for over in overs:
|
||||
if 'gigabytes' in over:
|
||||
s_size = volume['size']
|
||||
d_quota = quotas[over]
|
||||
d_consumed = _consumed(over)
|
||||
LOG.warning(
|
||||
_LW("Quota exceeded for %(s_pid)s, tried to create "
|
||||
"%(s_size)sG volume - (%(d_consumed)dG of "
|
||||
"%(d_quota)dG already consumed)"),
|
||||
{'s_pid': ctxt.project_id,
|
||||
's_size': s_size,
|
||||
'd_consumed': d_consumed,
|
||||
'd_quota': d_quota})
|
||||
raise exception.VolumeSizeExceedsAvailableQuota(
|
||||
requested=s_size, quota=d_quota, consumed=d_consumed)
|
||||
elif 'volumes' in over:
|
||||
LOG.warning(
|
||||
_LW("Quota exceeded for %(s_pid)s, tried to create "
|
||||
"volume (%(d_consumed)d volumes "
|
||||
"already consumed)"),
|
||||
{'s_pid': ctxt.project_id,
|
||||
'd_consumed': _consumed(over)})
|
||||
raise exception.VolumeLimitExceeded(
|
||||
allowed=quotas[over])
|
||||
process_reserve_over_quota(ctxt, e,
|
||||
resource='volumes',
|
||||
size=volume.size)
|
||||
return reservations
|
||||
|
||||
|
||||
|
@ -261,3 +233,65 @@ def _keystone_client(context, version=(3, 0)):
|
|||
(CONF.keystone_authtoken.cafile or True))
|
||||
return client.Client(auth_url=CONF.keystone_authtoken.auth_uri,
|
||||
session=client_session, version=version)
|
||||
|
||||
|
||||
OVER_QUOTA_RESOURCE_EXCEPTIONS = {'snapshots': exception.SnapshotLimitExceeded,
|
||||
'backups': exception.BackupLimitExceeded,
|
||||
'volumes': exception.VolumeLimitExceeded, }
|
||||
|
||||
|
||||
def process_reserve_over_quota(context, over_quota_exception,
|
||||
resource, size=None):
|
||||
"""Handle OverQuota exception.
|
||||
|
||||
Analyze OverQuota exception, and raise new exception related to
|
||||
resource type. If there are unexpected items in overs,
|
||||
UnexpectedOverQuota is raised.
|
||||
|
||||
:param context: security context
|
||||
:param over_quota_exception: OverQuota exception
|
||||
:param resource: can be backups, snapshots, and volumes
|
||||
:param size: requested size in reservation
|
||||
"""
|
||||
def _consumed(name):
|
||||
return (usages[name]['reserved'] + usages[name]['in_use'])
|
||||
|
||||
overs = over_quota_exception.kwargs['overs']
|
||||
usages = over_quota_exception.kwargs['usages']
|
||||
quotas = over_quota_exception.kwargs['quotas']
|
||||
invalid_overs = []
|
||||
|
||||
for over in overs:
|
||||
if 'gigabytes' in over:
|
||||
msg = _LW("Quota exceeded for %(s_pid)s, tried to create "
|
||||
"%(s_size)dG %(s_resource)s (%(d_consumed)dG of "
|
||||
"%(d_quota)dG already consumed).")
|
||||
LOG.warning(msg, {'s_pid': context.project_id,
|
||||
's_size': size,
|
||||
's_resource': resource[:-1],
|
||||
'd_consumed': _consumed(over),
|
||||
'd_quota': quotas[over]})
|
||||
if resource == 'backups':
|
||||
exc = exception.VolumeBackupSizeExceedsAvailableQuota
|
||||
else:
|
||||
exc = exception.VolumeSizeExceedsAvailableQuota
|
||||
raise exc(
|
||||
name=over,
|
||||
requested=size,
|
||||
consumed=_consumed(over),
|
||||
quota=quotas[over])
|
||||
if (resource in OVER_QUOTA_RESOURCE_EXCEPTIONS.keys() and
|
||||
resource in over):
|
||||
msg = _LW("Quota exceeded for %(s_pid)s, tried to create "
|
||||
"%(s_resource)s (%(d_consumed)d %(s_resource)ss "
|
||||
"already consumed).")
|
||||
LOG.warning(msg, {'s_pid': context.project_id,
|
||||
'd_consumed': _consumed(over),
|
||||
's_resource': resource[:-1]})
|
||||
raise OVER_QUOTA_RESOURCE_EXCEPTIONS[resource](
|
||||
allowed=quotas[over],
|
||||
name=over)
|
||||
invalid_overs.append(over)
|
||||
|
||||
if invalid_overs:
|
||||
raise exception.UnexpectedOverQuota(name=', '.join(invalid_overs))
|
||||
|
|
|
@ -165,3 +165,80 @@ class QuotaUtilsTest(test.TestCase):
|
|||
self.assertRaises(exception.CinderException,
|
||||
quota_utils.validate_setup_for_nested_quota_use,
|
||||
self.context, [], None)
|
||||
|
||||
def _process_reserve_over_quota(self, overs, usages, quotas,
|
||||
expected_ex,
|
||||
resource='volumes'):
|
||||
ctxt = context.get_admin_context()
|
||||
ctxt.project_id = 'fake'
|
||||
size = 1
|
||||
kwargs = {'overs': overs,
|
||||
'usages': usages,
|
||||
'quotas': quotas}
|
||||
exc = exception.OverQuota(**kwargs)
|
||||
|
||||
self.assertRaises(expected_ex,
|
||||
quota_utils.process_reserve_over_quota,
|
||||
ctxt, exc,
|
||||
resource=resource,
|
||||
size=size)
|
||||
|
||||
def test_volume_size_exceed_quota(self):
|
||||
overs = ['gigabytes']
|
||||
usages = {'gigabytes': {'reserved': 1, 'in_use': 9}}
|
||||
quotas = {'gigabytes': 10, 'snapshots': 10}
|
||||
self._process_reserve_over_quota(
|
||||
overs, usages, quotas,
|
||||
exception.VolumeSizeExceedsAvailableQuota)
|
||||
|
||||
def test_snapshot_limit_exceed_quota(self):
|
||||
overs = ['snapshots']
|
||||
usages = {'snapshots': {'reserved': 1, 'in_use': 9}}
|
||||
quotas = {'gigabytes': 10, 'snapshots': 10}
|
||||
self._process_reserve_over_quota(
|
||||
overs, usages, quotas,
|
||||
exception.SnapshotLimitExceeded,
|
||||
resource='snapshots')
|
||||
|
||||
def test_backup_gigabytes_exceed_quota(self):
|
||||
overs = ['backup_gigabytes']
|
||||
usages = {'backup_gigabytes': {'reserved': 1, 'in_use': 9}}
|
||||
quotas = {'backup_gigabytes': 10}
|
||||
self._process_reserve_over_quota(
|
||||
overs, usages, quotas,
|
||||
exception.VolumeBackupSizeExceedsAvailableQuota,
|
||||
resource='backups')
|
||||
|
||||
def test_backup_limit_quota(self):
|
||||
overs = ['backups']
|
||||
usages = {'backups': {'reserved': 1, 'in_use': 9}}
|
||||
quotas = {'backups': 9}
|
||||
self._process_reserve_over_quota(
|
||||
overs, usages, quotas,
|
||||
exception.BackupLimitExceeded,
|
||||
resource='backups')
|
||||
|
||||
def test_volumes_limit_quota(self):
|
||||
overs = ['volumes']
|
||||
usages = {'volumes': {'reserved': 1, 'in_use': 9}}
|
||||
quotas = {'volumes': 9}
|
||||
self._process_reserve_over_quota(
|
||||
overs, usages, quotas,
|
||||
exception.VolumeLimitExceeded)
|
||||
|
||||
def test_unknown_quota(self):
|
||||
overs = ['unknown']
|
||||
usages = {'volumes': {'reserved': 1, 'in_use': 9}}
|
||||
quotas = {'volumes': 9}
|
||||
self._process_reserve_over_quota(
|
||||
overs, usages, quotas,
|
||||
exception.UnexpectedOverQuota)
|
||||
|
||||
def test_unknown_quota2(self):
|
||||
overs = ['volumes']
|
||||
usages = {'volumes': {'reserved': 1, 'in_use': 9}}
|
||||
quotas = {'volumes': 9}
|
||||
self._process_reserve_over_quota(
|
||||
overs, usages, quotas,
|
||||
exception.UnexpectedOverQuota,
|
||||
resource='snapshots')
|
||||
|
|
|
@ -88,6 +88,12 @@ fake_opt = [
|
|||
]
|
||||
|
||||
|
||||
OVER_SNAPSHOT_QUOTA_EXCEPTION = exception.OverQuota(
|
||||
overs=['snapshots'],
|
||||
usages = {'snapshots': {'reserved': 1, 'in_use': 9}},
|
||||
quotas = {'gigabytes': 10, 'snapshots': 10})
|
||||
|
||||
|
||||
def create_snapshot(volume_id, size=1, metadata=None, ctxt=None,
|
||||
**kwargs):
|
||||
"""Create a snapshot object."""
|
||||
|
@ -3099,10 +3105,8 @@ class VolumeTestCase(BaseVolumeTestCase):
|
|||
"""Test exception handling when create snapshot in db failed."""
|
||||
test_volume = tests_utils.create_volume(
|
||||
self.context,
|
||||
**self.volume_params)
|
||||
self.volume.create_volume(self.context, test_volume.id,
|
||||
volume=test_volume)
|
||||
test_volume['status'] = 'available'
|
||||
status='available',
|
||||
host=CONF.host)
|
||||
volume_api = cinder.volume.api.API()
|
||||
self.assertRaises(exception.InvalidSnapshot,
|
||||
volume_api.create_snapshot,
|
||||
|
@ -3115,10 +3119,8 @@ class VolumeTestCase(BaseVolumeTestCase):
|
|||
"""Test exception handling when create snapshot in maintenance."""
|
||||
test_volume = tests_utils.create_volume(
|
||||
self.context,
|
||||
**self.volume_params)
|
||||
self.volume.create_volume(self.context, test_volume.id,
|
||||
volume=test_volume)
|
||||
test_volume['status'] = 'maintenance'
|
||||
status='maintenance',
|
||||
host=CONF.host)
|
||||
volume_api = cinder.volume.api.API()
|
||||
self.assertRaises(exception.InvalidVolume,
|
||||
volume_api.create_snapshot,
|
||||
|
@ -3134,10 +3136,8 @@ class VolumeTestCase(BaseVolumeTestCase):
|
|||
"""Test exception handling when snapshot quota commit failed."""
|
||||
test_volume = tests_utils.create_volume(
|
||||
self.context,
|
||||
**self.volume_params)
|
||||
self.volume.create_volume(self.context, test_volume.id,
|
||||
request_spec={}, volume=test_volume)
|
||||
test_volume['status'] = 'available'
|
||||
status='available',
|
||||
host=CONF.host)
|
||||
volume_api = cinder.volume.api.API()
|
||||
self.assertRaises(exception.QuotaError,
|
||||
volume_api.create_snapshot,
|
||||
|
@ -3146,6 +3146,40 @@ class VolumeTestCase(BaseVolumeTestCase):
|
|||
'fake_name',
|
||||
'fake_description')
|
||||
|
||||
@mock.patch.object(QUOTAS, 'reserve',
|
||||
side_effect = OVER_SNAPSHOT_QUOTA_EXCEPTION)
|
||||
def test_create_snapshot_failed_quota_reserve(self, mock_reserve):
|
||||
"""Test exception handling when snapshot quota reserve failed."""
|
||||
test_volume = tests_utils.create_volume(
|
||||
self.context,
|
||||
status='available',
|
||||
host=CONF.host)
|
||||
volume_api = cinder.volume.api.API()
|
||||
self.assertRaises(exception.SnapshotLimitExceeded,
|
||||
volume_api.create_snapshot,
|
||||
self.context,
|
||||
test_volume,
|
||||
'fake_name',
|
||||
'fake_description')
|
||||
|
||||
@mock.patch.object(QUOTAS, 'reserve',
|
||||
side_effect = OVER_SNAPSHOT_QUOTA_EXCEPTION)
|
||||
def test_create_snapshots_in_db_failed_quota_reserve(self, mock_reserve):
|
||||
"""Test exception handling when snapshot quota reserve failed."""
|
||||
test_volume = tests_utils.create_volume(
|
||||
self.context,
|
||||
status='available',
|
||||
host=CONF.host)
|
||||
volume_api = cinder.volume.api.API()
|
||||
self.assertRaises(exception.SnapshotLimitExceeded,
|
||||
volume_api.create_snapshots_in_db,
|
||||
self.context,
|
||||
[test_volume],
|
||||
'fake_name',
|
||||
'fake_description',
|
||||
False,
|
||||
fake.CONSISTENCY_GROUP_ID)
|
||||
|
||||
def test_cannot_delete_volume_in_use(self):
|
||||
"""Test volume can't be deleted in in-use status."""
|
||||
self._test_cannot_delete_volume('in-use')
|
||||
|
@ -4519,6 +4553,20 @@ class VolumeTestCase(BaseVolumeTestCase):
|
|||
'is_snapshot': False}
|
||||
self.assertEqual(expected_result, result)
|
||||
|
||||
@mock.patch.object(QUOTAS, 'reserve',
|
||||
side_effect = OVER_SNAPSHOT_QUOTA_EXCEPTION)
|
||||
def test_existing_snapshot_failed_quota_reserve(self, mock_reserve):
|
||||
vol = tests_utils.create_volume(self.context)
|
||||
snap = tests_utils.create_snapshot(self.context, vol.id)
|
||||
with mock.patch.object(
|
||||
self.volume.driver,
|
||||
'manage_existing_snapshot_get_size') as mock_get_size:
|
||||
mock_get_size.return_value = 1
|
||||
self.assertRaises(exception.SnapshotLimitExceeded,
|
||||
self.volume.manage_existing_snapshot,
|
||||
self.context,
|
||||
snap)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class VolumeMigrationTestCase(BaseVolumeTestCase):
|
||||
|
|
|
@ -816,20 +816,3 @@ class VolumeUtilsTestCase(test.TestCase):
|
|||
self.assertEqual(
|
||||
expected_dict,
|
||||
volume_utils.convert_config_string_to_dict(test_string))
|
||||
|
||||
def test_process_reserve_over_quota(self):
|
||||
ctxt = context.get_admin_context()
|
||||
ctxt.project_id = 'fake'
|
||||
overs_one = ['gigabytes']
|
||||
over_two = ['snapshots']
|
||||
usages = {'gigabytes': {'reserved': 1, 'in_use': 9},
|
||||
'snapshots': {'reserved': 1, 'in_use': 9}}
|
||||
quotas = {'gigabytes': 10, 'snapshots': 10}
|
||||
size = 1
|
||||
|
||||
self.assertRaises(exception.VolumeSizeExceedsAvailableQuota,
|
||||
volume_utils.process_reserve_over_quota,
|
||||
ctxt, overs_one, usages, quotas, size)
|
||||
self.assertRaises(exception.SnapshotLimitExceeded,
|
||||
volume_utils.process_reserve_over_quota,
|
||||
ctxt, over_two, usages, quotas, size)
|
||||
|
|
|
@ -29,8 +29,9 @@ import six
|
|||
|
||||
from cinder.db import base
|
||||
from cinder import exception
|
||||
from cinder.i18n import _, _LE, _LI, _LW
|
||||
from cinder.i18n import _, _LE, _LI
|
||||
from cinder import quota
|
||||
from cinder import quota_utils
|
||||
from cinder.volume import api as volume_api
|
||||
from cinder.volume import utils as volume_utils
|
||||
|
||||
|
@ -178,35 +179,9 @@ class API(base.Base):
|
|||
vol_ref.volume_type_id)
|
||||
reservations = QUOTAS.reserve(context, **reserve_opts)
|
||||
except exception.OverQuota as e:
|
||||
overs = e.kwargs['overs']
|
||||
usages = e.kwargs['usages']
|
||||
quotas = e.kwargs['quotas']
|
||||
|
||||
def _consumed(name):
|
||||
return (usages[name]['reserved'] + usages[name]['in_use'])
|
||||
|
||||
for over in overs:
|
||||
if 'gigabytes' in over:
|
||||
msg = _LW("Quota exceeded for %(s_pid)s, tried to create "
|
||||
"%(s_size)sG volume (%(d_consumed)dG of "
|
||||
"%(d_quota)dG already consumed)")
|
||||
LOG.warning(msg, {'s_pid': context.project_id,
|
||||
's_size': vol_ref['size'],
|
||||
'd_consumed': _consumed(over),
|
||||
'd_quota': quotas[over]})
|
||||
raise exception.VolumeSizeExceedsAvailableQuota(
|
||||
requested=vol_ref['size'],
|
||||
consumed=_consumed(over),
|
||||
quota=quotas[over])
|
||||
elif 'volumes' in over:
|
||||
msg = _LW("Quota exceeded for %(s_pid)s, tried to create "
|
||||
"volume (%(d_consumed)d volumes "
|
||||
"already consumed)")
|
||||
LOG.warning(msg, {'s_pid': context.project_id,
|
||||
'd_consumed': _consumed(over)})
|
||||
raise exception.VolumeLimitExceeded(allowed=quotas[over],
|
||||
name=over)
|
||||
|
||||
quota_utils.process_reserve_over_quota(context, e,
|
||||
resource='volumes',
|
||||
size=vol_ref.size)
|
||||
try:
|
||||
donor_id = vol_ref['project_id']
|
||||
reserve_opts = {'volumes': -1, 'gigabytes': -vol_ref.size}
|
||||
|
|
|
@ -750,36 +750,10 @@ class API(base.Base):
|
|||
volume.get('volume_type_id'))
|
||||
reservations = QUOTAS.reserve(context, **reserve_opts)
|
||||
except exception.OverQuota as e:
|
||||
overs = e.kwargs['overs']
|
||||
usages = e.kwargs['usages']
|
||||
quotas = e.kwargs['quotas']
|
||||
|
||||
def _consumed(name):
|
||||
return (usages[name]['reserved'] + usages[name]['in_use'])
|
||||
|
||||
for over in overs:
|
||||
if 'gigabytes' in over:
|
||||
msg = _LW("Quota exceeded for %(s_pid)s, tried to "
|
||||
"create %(s_size)sG snapshot (%(d_consumed)d"
|
||||
"G of %(d_quota)dG already consumed).")
|
||||
LOG.warning(msg, {'s_pid': context.project_id,
|
||||
's_size': volume['size'],
|
||||
'd_consumed': _consumed(over),
|
||||
'd_quota': quotas[over]})
|
||||
raise exception.VolumeSizeExceedsAvailableQuota(
|
||||
requested=volume['size'],
|
||||
consumed=_consumed('gigabytes'),
|
||||
quota=quotas['gigabytes'])
|
||||
elif 'snapshots' in over:
|
||||
msg = _LW("Quota exceeded for %(s_pid)s, tried to "
|
||||
"create snapshot (%(d_consumed)d snapshots "
|
||||
"already consumed).")
|
||||
|
||||
LOG.warning(msg, {'s_pid': context.project_id,
|
||||
'd_consumed': _consumed(over)})
|
||||
raise exception.SnapshotLimitExceeded(
|
||||
allowed=quotas[over])
|
||||
|
||||
quota_utils.process_reserve_over_quota(
|
||||
context, e,
|
||||
resource='snapshots',
|
||||
size=volume.size)
|
||||
self._check_metadata_properties(metadata)
|
||||
|
||||
snapshot = None
|
||||
|
@ -893,11 +867,9 @@ class API(base.Base):
|
|||
total_reserve_opts[key] + value
|
||||
reservations = QUOTAS.reserve(context, **total_reserve_opts)
|
||||
except exception.OverQuota as e:
|
||||
overs = e.kwargs['overs']
|
||||
usages = e.kwargs['usages']
|
||||
quotas = e.kwargs['quotas']
|
||||
volume_utils.process_reserve_over_quota(context, overs, usages,
|
||||
quotas, volume['size'])
|
||||
quota_utils.process_reserve_over_quota(context, e,
|
||||
resource='snapshots',
|
||||
size=volume.size)
|
||||
|
||||
return reservations
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ from cinder import objects
|
|||
from cinder.objects import fields
|
||||
from cinder import policy
|
||||
from cinder import quota
|
||||
from cinder import quota_utils
|
||||
from cinder import utils
|
||||
from cinder.volume.flows import common
|
||||
from cinder.volume import utils as vol_utils
|
||||
|
@ -601,53 +602,9 @@ class QuotaReserveTask(flow_utils.CinderTask):
|
|||
'reservations': reservations,
|
||||
}
|
||||
except exception.OverQuota as e:
|
||||
overs = e.kwargs['overs']
|
||||
quotas = e.kwargs['quotas']
|
||||
usages = e.kwargs['usages']
|
||||
|
||||
def _consumed(name):
|
||||
usage = usages[name]
|
||||
return usage['reserved'] + usage['in_use'] + usage.get(
|
||||
'allocated', 0)
|
||||
|
||||
def _get_over(name):
|
||||
for over in overs:
|
||||
if name in over:
|
||||
return over
|
||||
return None
|
||||
|
||||
over_name = _get_over('gigabytes')
|
||||
exceeded_vol_limit_name = _get_over('volumes')
|
||||
if over_name:
|
||||
# TODO(mc_nair): improve error message for child -1 limit
|
||||
msg = _LW("Quota exceeded for %(s_pid)s, tried to create "
|
||||
"%(s_size)sG volume (%(d_consumed)dG "
|
||||
"of %(d_quota)dG already consumed)")
|
||||
LOG.warning(msg, {'s_pid': context.project_id,
|
||||
's_size': size,
|
||||
'd_consumed': _consumed(over_name),
|
||||
'd_quota': quotas[over_name]})
|
||||
raise exception.VolumeSizeExceedsAvailableQuota(
|
||||
name=over_name,
|
||||
requested=size,
|
||||
consumed=_consumed(over_name),
|
||||
quota=quotas[over_name])
|
||||
elif exceeded_vol_limit_name:
|
||||
msg = _LW("Quota %(s_name)s exceeded for %(s_pid)s, tried "
|
||||
"to create volume (%(d_consumed)d volume(s) "
|
||||
"already consumed).")
|
||||
LOG.warning(msg,
|
||||
{'s_name': exceeded_vol_limit_name,
|
||||
's_pid': context.project_id,
|
||||
'd_consumed':
|
||||
_consumed(exceeded_vol_limit_name)})
|
||||
# TODO(mc_nair): improve error message for child -1 limit
|
||||
raise exception.VolumeLimitExceeded(
|
||||
allowed=quotas[exceeded_vol_limit_name],
|
||||
name=exceeded_vol_limit_name)
|
||||
else:
|
||||
# If nothing was reraised, ensure we reraise the initial error
|
||||
raise
|
||||
quota_utils.process_reserve_over_quota(context, e,
|
||||
resource='volumes',
|
||||
size=size)
|
||||
|
||||
def revert(self, context, result, optional_args, **kwargs):
|
||||
# We never produced a result and therefore can't destroy anything.
|
||||
|
|
|
@ -23,6 +23,7 @@ from cinder import flow_utils
|
|||
from cinder.i18n import _, _LE, _LI
|
||||
from cinder import objects
|
||||
from cinder import quota
|
||||
from cinder import quota_utils
|
||||
from cinder.volume.flows import common as flow_common
|
||||
from cinder.volume import utils as volume_utils
|
||||
|
||||
|
@ -153,11 +154,10 @@ class QuotaReserveTask(flow_utils.CinderTask):
|
|||
'reservations': reservations,
|
||||
}
|
||||
except exception.OverQuota as e:
|
||||
overs = e.kwargs['overs']
|
||||
quotas = e.kwargs['quotas']
|
||||
usages = e.kwargs['usages']
|
||||
volume_utils.process_reserve_over_quota(context, overs, usages,
|
||||
quotas, size)
|
||||
quota_utils.process_reserve_over_quota(
|
||||
context, e,
|
||||
resource='snapshots',
|
||||
size=size)
|
||||
|
||||
def revert(self, context, result, optional_args, **kwargs):
|
||||
# We never produced a result and therefore can't destroy anything.
|
||||
|
|
|
@ -710,29 +710,3 @@ def convert_config_string_to_dict(config_string):
|
|||
{'config_string': config_string})
|
||||
|
||||
return resultant_dict
|
||||
|
||||
|
||||
def process_reserve_over_quota(context, overs, usages, quotas, size):
|
||||
def _consumed(name):
|
||||
return (usages[name]['reserved'] + usages[name]['in_use'])
|
||||
|
||||
for over in overs:
|
||||
if 'gigabytes' in over:
|
||||
msg = _LW("Quota exceeded for %(s_pid)s, tried to create "
|
||||
"%(s_size)sG snapshot (%(d_consumed)dG of "
|
||||
"%(d_quota)dG already consumed).")
|
||||
LOG.warning(msg, {'s_pid': context.project_id,
|
||||
's_size': size,
|
||||
'd_consumed': _consumed(over),
|
||||
'd_quota': quotas[over]})
|
||||
raise exception.VolumeSizeExceedsAvailableQuota(
|
||||
requested=size,
|
||||
consumed=_consumed('gigabytes'),
|
||||
quota=quotas['gigabytes'])
|
||||
elif 'snapshots' in over:
|
||||
msg = _LW("Quota exceeded for %(s_pid)s, tried to create "
|
||||
"snapshot (%(d_consumed)d snapshots "
|
||||
"already consumed).")
|
||||
LOG.warning(msg, {'s_pid': context.project_id,
|
||||
'd_consumed': _consumed(over)})
|
||||
raise exception.SnapshotLimitExceeded(allowed=quotas[over])
|
||||
|
|
Loading…
Reference in New Issue