From 3d3eb35c1391cd0aa639230b34402c580858b281 Mon Sep 17 00:00:00 2001 From: silvacarloss Date: Mon, 20 Apr 2020 18:24:34 +0000 Subject: [PATCH] Fix manila OverQuota issue while managing shares Fixes the OverQuota issue while managing shares. Now, when a share manage request is received and there is no available quota to this resource, manila will allow the quotas to be exceeded and the administrator will need to adjust it. Change-Id: If6edfa79965f1a0e6959b436c53a714217d23f7d Closes-Bug: #1863298 (cherry picked from commit 413e5e6d08789d39897b5db24f2fc1371d24ced2) --- manila/db/api.py | 5 ++-- manila/db/sqlalchemy/api.py | 27 ++++++++++++++++--- manila/quota.py | 8 +++--- manila/share/manager.py | 9 ++++++- manila/tests/share/test_manager.py | 1 + manila/tests/test_quota.py | 4 ++- ...nage-overquota-issue-37031a593b66f8ba.yaml | 10 +++++++ 7 files changed, 53 insertions(+), 11 deletions(-) create mode 100644 releasenotes/notes/bug-1863298-fix-manage-overquota-issue-37031a593b66f8ba.yaml diff --git a/manila/db/api.py b/manila/db/api.py index 73c1bba153..80b38113fd 100644 --- a/manila/db/api.py +++ b/manila/db/api.py @@ -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, diff --git a/manila/db/sqlalchemy/api.py b/manila/db/sqlalchemy/api.py index 415513fbdd..9ecfcf61ec 100644 --- a/manila/db/sqlalchemy/api.py +++ b/manila/db/sqlalchemy/api.py @@ -933,16 +933,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 @@ -956,7 +959,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(): @@ -1104,6 +1108,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 diff --git a/manila/quota.py b/manila/quota.py index cde0d63955..a5a691551c 100644 --- a/manila/quota.py +++ b/manila/quota.py @@ -384,7 +384,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 @@ -465,7 +466,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): @@ -876,7 +877,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 @@ -917,6 +918,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) diff --git a/manila/share/manager.py b/manila/share/manager.py index 07f9817c32..f72d4badab 100644 --- a/manila/share/manager.py +++ b/manila/share/manager.py @@ -2480,7 +2480,14 @@ class ShareManager(manager.SchedulerDependentManager): deltas.update({'share_replicas': 1, 'replica_gigabytes': share_update['size']}) - reservations = QUOTAS.reserve(context, **deltas) + # 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, overquota_allowed=True, + **deltas) QUOTAS.commit( context, reservations, project_id=project_id, share_type_id=share_instance['share_type_id'], diff --git a/manila/tests/share/test_manager.py b/manila/tests/share/test_manager.py index 8d10351656..70cfed9d48 100644 --- a/manila/tests/share/test_manager.py +++ b/manila/tests/share/test_manager.py @@ -2748,6 +2748,7 @@ class ShareManagerTestCase(test.TestCase): 'shares': 1, 'gigabytes': driver_data['size'], 'share_type_id': share['instance']['share_type_id'], + 'overquota_allowed': True } if replication_type: expected_deltas.update({'share_replicas': 1, diff --git a/manila/tests/test_quota.py b/manila/tests/test_quota.py index d2874c5237..d13dbcd934 100644 --- a/manila/tests/test_quota.py +++ b/manila/tests/test_quota.py @@ -354,6 +354,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 {} @@ -625,7 +626,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): diff --git a/releasenotes/notes/bug-1863298-fix-manage-overquota-issue-37031a593b66f8ba.yaml b/releasenotes/notes/bug-1863298-fix-manage-overquota-issue-37031a593b66f8ba.yaml new file mode 100644 index 0000000000..e21d46ff97 --- /dev/null +++ b/releasenotes/notes/bug-1863298-fix-manage-overquota-issue-37031a593b66f8ba.yaml @@ -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 `_ for + more details.