Merge "Fix manila OverQuota issue while managing shares" into stable/train
This commit is contained in:
commit
5e2fc65268
|
@ -250,12 +250,13 @@ def quota_usage_update(context, project_id, user_id, resource,
|
|||
|
||||
def quota_reserve(context, resources, quotas, user_quotas, share_type_quotas,
|
||||
deltas, expire, until_refresh, max_age,
|
||||
project_id=None, user_id=None, share_type_id=None):
|
||||
project_id=None, user_id=None, share_type_id=None,
|
||||
overquota_allowed=False):
|
||||
"""Check quotas and create appropriate reservations."""
|
||||
return IMPL.quota_reserve(
|
||||
context, resources, quotas, user_quotas, share_type_quotas, deltas,
|
||||
expire, until_refresh, max_age, project_id=project_id, user_id=user_id,
|
||||
share_type_id=share_type_id)
|
||||
share_type_id=share_type_id, overquota_allowed=overquota_allowed)
|
||||
|
||||
|
||||
def reservation_commit(context, reservations, project_id=None, user_id=None,
|
||||
|
|
|
@ -914,16 +914,19 @@ def _get_project_quota_usages(context, session, project_id):
|
|||
@require_context
|
||||
def quota_reserve(context, resources, project_quotas, user_quotas,
|
||||
share_type_quotas, deltas, expire, until_refresh,
|
||||
max_age, project_id=None, user_id=None, share_type_id=None):
|
||||
max_age, project_id=None, user_id=None, share_type_id=None,
|
||||
overquota_allowed=False):
|
||||
user_reservations = _quota_reserve(
|
||||
context, resources, project_quotas, user_quotas,
|
||||
deltas, expire, until_refresh, max_age, project_id, user_id=user_id)
|
||||
deltas, expire, until_refresh, max_age, project_id, user_id=user_id,
|
||||
overquota_allowed=overquota_allowed)
|
||||
if share_type_id:
|
||||
try:
|
||||
st_reservations = _quota_reserve(
|
||||
context, resources, project_quotas, share_type_quotas,
|
||||
deltas, expire, until_refresh, max_age, project_id,
|
||||
share_type_id=share_type_id)
|
||||
share_type_id=share_type_id,
|
||||
overquota_allowed=overquota_allowed)
|
||||
except exception.OverQuota:
|
||||
with excutils.save_and_reraise_exception():
|
||||
# rollback previous reservations
|
||||
|
@ -937,7 +940,8 @@ def quota_reserve(context, resources, project_quotas, user_quotas,
|
|||
@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True)
|
||||
def _quota_reserve(context, resources, project_quotas, user_or_st_quotas,
|
||||
deltas, expire, until_refresh,
|
||||
max_age, project_id=None, user_id=None, share_type_id=None):
|
||||
max_age, project_id=None, user_id=None, share_type_id=None,
|
||||
overquota_allowed=False):
|
||||
elevated = context.elevated()
|
||||
session = get_session()
|
||||
with session.begin():
|
||||
|
@ -1085,6 +1089,21 @@ def _quota_reserve(context, resources, project_quotas, user_or_st_quotas,
|
|||
user_or_st_quotas[res] < delta +
|
||||
user_or_st_usages[res].total)]
|
||||
|
||||
# NOTE(carloss): If OverQuota is allowed, there is no problem to exceed
|
||||
# the quotas, so we reset the overs list and LOG it.
|
||||
if overs and overquota_allowed:
|
||||
msg = _("The service has identified one or more exceeded "
|
||||
"quotas. Please check the quotas for project "
|
||||
"%(project_id)s, user %(user_id)s and share type "
|
||||
"%(share_type_id)s, and adjust them if "
|
||||
"necessary.") % {
|
||||
"project_id": project_id,
|
||||
"user_id": user_id,
|
||||
"share_type_id": share_type_id
|
||||
}
|
||||
LOG.warning(msg)
|
||||
overs = []
|
||||
|
||||
# NOTE(Vek): The quota check needs to be in the transaction,
|
||||
# but the transaction doesn't fail just because
|
||||
# we're over quota, so the OverQuota raise is
|
||||
|
|
|
@ -378,7 +378,8 @@ class DbQuotaDriver(object):
|
|||
return {k: v['limit'] for k, v in quotas.items()}
|
||||
|
||||
def reserve(self, context, resources, deltas, expire=None,
|
||||
project_id=None, user_id=None, share_type_id=None):
|
||||
project_id=None, user_id=None, share_type_id=None,
|
||||
overquota_allowed=False):
|
||||
"""Check quotas and reserve resources.
|
||||
|
||||
For counting quotas--those quotas for which there is a usage
|
||||
|
@ -459,7 +460,7 @@ class DbQuotaDriver(object):
|
|||
context, resources, quotas, user_quotas, share_type_quotas,
|
||||
deltas, expire, CONF.until_refresh, CONF.max_age,
|
||||
project_id=project_id, user_id=user_id,
|
||||
share_type_id=share_type_id)
|
||||
share_type_id=share_type_id, overquota_allowed=overquota_allowed)
|
||||
|
||||
def commit(self, context, reservations, project_id=None, user_id=None,
|
||||
share_type_id=None):
|
||||
|
@ -870,7 +871,7 @@ class QuotaEngine(object):
|
|||
return res.count(context, *args, **kwargs)
|
||||
|
||||
def reserve(self, context, expire=None, project_id=None, user_id=None,
|
||||
share_type_id=None, **deltas):
|
||||
share_type_id=None, overquota_allowed=False, **deltas):
|
||||
"""Check quotas and reserve resources.
|
||||
|
||||
For counting quotas--those quotas for which there is a usage
|
||||
|
@ -911,6 +912,7 @@ class QuotaEngine(object):
|
|||
project_id=project_id,
|
||||
user_id=user_id,
|
||||
share_type_id=share_type_id,
|
||||
overquota_allowed=overquota_allowed
|
||||
)
|
||||
|
||||
LOG.debug("Created reservations %s", reservations)
|
||||
|
|
|
@ -2420,6 +2420,12 @@ class ShareManager(manager.SchedulerDependentManager):
|
|||
msg = _("Driver cannot calculate share size.")
|
||||
raise exception.InvalidShare(reason=msg)
|
||||
|
||||
# NOTE(carloss): Allowing OverQuota to do not compromise this
|
||||
# operation. If this hit OverQuota error while managing a share,
|
||||
# the admin would need to reset the state of the share and
|
||||
# delete or force delete the share (bug 1863298). Allowing
|
||||
# OverQuota makes this operation work properly and the admin will
|
||||
# need to adjust quotas afterwards.
|
||||
reservations = QUOTAS.reserve(
|
||||
context,
|
||||
project_id=project_id,
|
||||
|
@ -2427,6 +2433,7 @@ class ShareManager(manager.SchedulerDependentManager):
|
|||
shares=1,
|
||||
gigabytes=share_update['size'],
|
||||
share_type_id=share_instance['share_type_id'],
|
||||
overquota_allowed=True
|
||||
)
|
||||
QUOTAS.commit(
|
||||
context, reservations, project_id=project_id,
|
||||
|
|
|
@ -2621,6 +2621,14 @@ class ShareManagerTestCase(test.TestCase):
|
|||
share = db_utils.create_share(replication_type=replication_type)
|
||||
share_id = share['id']
|
||||
driver_options = {'fake': 'fake'}
|
||||
expected_deltas = {
|
||||
'project_id': share['project_id'],
|
||||
'user_id': self.context.user_id,
|
||||
'shares': 1,
|
||||
'gigabytes': driver_data['size'],
|
||||
'share_type_id': share['instance']['share_type_id'],
|
||||
'overquota_allowed': True
|
||||
}
|
||||
|
||||
self.share_manager.manage_share(self.context, share_id, driver_options)
|
||||
|
||||
|
@ -2644,6 +2652,8 @@ class ShareManagerTestCase(test.TestCase):
|
|||
self.share_manager.db.share_update.assert_called_once_with(
|
||||
utils.IsAMatcher(context.RequestContext),
|
||||
share_id, valid_share_data)
|
||||
quota.QUOTAS.reserve.assert_called_once_with(
|
||||
mock.ANY, **expected_deltas)
|
||||
|
||||
def test_update_quota_usages_new(self):
|
||||
self.mock_object(self.share_manager.db, 'quota_usage_get',
|
||||
|
|
|
@ -353,6 +353,7 @@ class DbQuotaDriverTestCase(test.TestCase):
|
|||
'project_id': self.ctxt.project_id,
|
||||
'user_id': self.ctxt.user_id,
|
||||
'share_type_id': None,
|
||||
'overquota_allowed': False
|
||||
}
|
||||
expected_kwargs.update(kwargs)
|
||||
st_quotas = st_quotas if kwargs.get('share_type_id') else {}
|
||||
|
@ -624,7 +625,8 @@ class QuotaEngineTestCase(test.TestCase):
|
|||
self.driver.reserve.assert_called_once_with(
|
||||
self.ctxt, self.engine._resources, {'delta1': 1, 'delta2': 2},
|
||||
expire='fake_expire', project_id=self.project_id,
|
||||
user_id=self.user_id, share_type_id=self.share_type_id)
|
||||
user_id=self.user_id, share_type_id=self.share_type_id,
|
||||
overquota_allowed=False)
|
||||
|
||||
@ddt.data(Exception('FakeException'), [None])
|
||||
def test_commit(self, side_effect):
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
fixes:
|
||||
- |
|
||||
Fixed an issue while bringing shares under Manila management. Now, when
|
||||
a share is being managed and there is no available quota to complete
|
||||
this operation, the service will allow the quotas to be exceeded and the
|
||||
operation will be completed. The administrator will need to adjust the
|
||||
quotas after. Please see
|
||||
`Launchpad bug <https://bugs.launchpad.net/manila/+bug/1863298>`_ for
|
||||
more details.
|
Loading…
Reference in New Issue