From 8229572c1d31d2bc686282eab48dd0465f023315 Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Fri, 3 Nov 2017 16:07:26 +0800 Subject: [PATCH] Support -1 as unlimited quota restraint in Trove. In other projects like nova and neutron, hard limit -1 often means unlimited quota restraint. But Trove dose not support that. This patch aims at two things: 1. Support -1, as unlimited quota restraint in check_quotas() 2. Add quota check to accept only -1, not -2 or other negative numbers when updating quotas. Change-Id: I028e6d7814ff240aa3f697e3d6ac8c7bac5bf3fd Closes-bug: #1729791 Signed-off-by: Fan Zhang --- trove/common/exception.py | 6 ++++ trove/extensions/mgmt/quota/service.py | 3 ++ trove/quota/quota.py | 1 + trove/tests/unittests/quota/test_quota.py | 37 +++++++++++++++++++++++ 4 files changed, 47 insertions(+) diff --git a/trove/common/exception.py b/trove/common/exception.py index 58f81f9764..509f524352 100644 --- a/trove/common/exception.py +++ b/trove/common/exception.py @@ -206,6 +206,12 @@ class OverLimit(TroveError): "rate.") +class QuotaLimitTooSmall(TroveError): + + message = _("Quota limit '%(limit)s' for '%(resource)s' is too small" + " - must be at least '-1'.") + + class QuotaExceeded(TroveError): message = _("Quota exceeded for resources: %(overs)s.") diff --git a/trove/extensions/mgmt/quota/service.py b/trove/extensions/mgmt/quota/service.py index 1786160c7a..b61f4fb295 100644 --- a/trove/extensions/mgmt/quota/service.py +++ b/trove/extensions/mgmt/quota/service.py @@ -55,6 +55,9 @@ class QuotaController(wsgi.Controller): for resource, limit in body['quotas'].items(): if limit is None: continue + elif limit < -1: + raise exception.QuotaLimitTooSmall(limit=limit, + resource=resource) if resource == "xmlns": continue if resource not in registered_resources: diff --git a/trove/quota/quota.py b/trove/quota/quota.py index 24931b7215..ee33f88675 100644 --- a/trove/quota/quota.py +++ b/trove/quota/quota.py @@ -147,6 +147,7 @@ class DbQuotaDriver(object): overs = [resource for resource in deltas if (int(deltas[resource]) > 0 and + quotas[resource].hard_limit >= 0 and (quota_usages[resource].in_use + quota_usages[resource].reserved + int(deltas[resource])) > quotas[resource].hard_limit)] diff --git a/trove/tests/unittests/quota/test_quota.py b/trove/tests/unittests/quota/test_quota.py index 37c8d46eae..9d33e31d19 100644 --- a/trove/tests/unittests/quota/test_quota.py +++ b/trove/tests/unittests/quota/test_quota.py @@ -144,6 +144,15 @@ class QuotaControllerTest(trove_testtools.TestCase): self.assertEqual(200, result.status) self.assertEqual(10, result._data['quotas']['volumes']) + def test_update_resource_with_invalid_negative_number(self): + quota = MagicMock(spec=Quota) + with patch.object(DatabaseModelBase, 'find_by', return_value=quota): + body = {'quotas': {'instances': -2}} + self.assertRaises(exception.QuotaLimitTooSmall, + self.controller.update, + self.req, body, FAKE_TENANT1, + FAKE_TENANT2) + class DbQuotaDriverTest(trove_testtools.TestCase): @@ -386,6 +395,34 @@ class DbQuotaDriverTest(trove_testtools.TestCase): self.assertEqual(0, usages[Resource.VOLUMES].in_use) self.assertEqual(0, usages[Resource.VOLUMES].reserved) + def test_check_quota_with_unlimited_quota(self): + + FAKE_QUOTA_USAGE = [QuotaUsage(id=1, + tenant_id=FAKE_TENANT1, + resource=Resource.INSTANCES, + in_use=1, + reserved=2), + QuotaUsage(id=2, + tenant_id=FAKE_TENANT1, + resource=Resource.VOLUMES, + in_use=1, + reserved=1)] + FAKE_QUOTAS = [Quota(tenant_id=FAKE_TENANT1, + resource=Resource.INSTANCES, + hard_limit=-1), + Quota(tenant_id=FAKE_TENANT1, + resource=Resource.VOLUMES, + hard_limit=-1)] + + self.mock_quota_result.all = Mock(return_value=FAKE_QUOTAS) + self.mock_usage_result.all = Mock(return_value=FAKE_QUOTA_USAGE) + QuotaUsage.save = Mock() + Reservation.create = Mock() + + delta = {'instances': 2, 'volumes': 3} + self.assertIsNone(self.driver.check_quotas(FAKE_TENANT1, resources, + delta)) + def test_reserve(self): FAKE_QUOTAS = [QuotaUsage(id=1,