From: Raildo Mascena Date: Wed, 28 Oct 2015 20:50:44 +0000 (-0300) Subject: Include allocated quota value in the quota reserve X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=5e5c66be483029c6b5861d8c268f1df345850a0d;p=openstack-build%2Fcinder-build.git Include allocated quota value in the quota reserve When we do a quota_reserve in a project, the allocated quota for their subprojects was not considered in the over quota calculation Co-Authored-By: Paulo Ewerton Change-Id: Ia72e13a40e00c4ec0e986b80a7c9a322f3df659d Closes-Bug: #1505801 --- diff --git a/cinder/db/sqlalchemy/api.py b/cinder/db/sqlalchemy/api.py index e82edd890..b603a2178 100644 --- a/cinder/db/sqlalchemy/api.py +++ b/cinder/db/sqlalchemy/api.py @@ -774,6 +774,8 @@ def quota_reserve(context, resources, quotas, deltas, expire, # Get the current usages usages = _get_quota_usages(context, session, project_id) + allocated = quota_allocated_get_all_by_project(context, project_id) + allocated.pop('project_id') # Handle usage refresh work = set(deltas.keys()) @@ -854,7 +856,7 @@ def quota_reserve(context, resources, quotas, deltas, expire, # problems. overs = [r for r, delta in deltas.items() if quotas[r] >= 0 and delta >= 0 and - quotas[r] < delta + usages[r].total] + quotas[r] < delta + usages[r].total + allocated.get(r, 0)] # NOTE(Vek): The quota check needs to be in the transaction, # but the transaction doesn't fail just because diff --git a/cinder/tests/unit/test_quota.py b/cinder/tests/unit/test_quota.py index 11f792d44..911556ff5 100644 --- a/cinder/tests/unit/test_quota.py +++ b/cinder/tests/unit/test_quota.py @@ -1584,12 +1584,56 @@ class QuotaReserveSqlAlchemyTestCase(test.TestCase): self.assertEqual(0, len(reservations)) + def _stub_allocated_get_all_by_project(self, allocated_quota=False): + def fake_qagabp(context, project_id): + self.assertEqual('test_project', project_id) + if allocated_quota: + return dict(project_id=project_id, volumes=3, + gigabytes = 2 * 1024) + return dict(project_id=project_id) + + self.stubs.Set(sqa_api, + 'quota_allocated_get_all_by_project', + fake_qagabp) + + def test_quota_reserve_with_allocated(self): + context = FakeContext('test_project', 'test_class') + # Allocated quota for volume will be updated for 3 + self._stub_allocated_get_all_by_project(allocated_quota=True) + # Quota limited for volume updated for 10 + quotas = dict(volumes=10, + gigabytes=10 * 1024, ) + # Try reserve 7 volumes + deltas = dict(volumes=7, + gigabytes=2 * 1024, ) + result = sqa_api.quota_reserve(context, self.resources, quotas, + deltas, self.expire, 5, 0) + # The reservation works + self.compare_reservation( + result, + [dict(resource='volumes', + usage_id=self.usages_created['volumes'], + project_id='test_project', + delta=7), + dict(resource='gigabytes', + usage_id=self.usages_created['gigabytes'], + delta=2 * 1024), ]) + # But if we try reserve 8 volumes(more free quota that we have) + deltas = dict(volumes=8, + gigabytes=2 * 1024, ) + + self.assertRaises(exception.OverQuota, + sqa_api.quota_reserve, + context, self.resources, quotas, + deltas, self.expire, 0, 0) + def test_quota_reserve_create_usages(self): context = FakeContext('test_project', 'test_class') quotas = dict(volumes=5, gigabytes=10 * 1024, ) deltas = dict(volumes=2, gigabytes=2 * 1024, ) + self._stub_allocated_get_all_by_project() result = sqa_api.quota_reserve(context, self.resources, quotas, deltas, self.expire, 0, 0) @@ -1623,6 +1667,7 @@ class QuotaReserveSqlAlchemyTestCase(test.TestCase): gigabytes=10 * 1024, ) deltas = dict(volumes=2, gigabytes=2 * 1024, ) + self._stub_allocated_get_all_by_project() result = sqa_api.quota_reserve(context, self.resources, quotas, deltas, self.expire, 5, 0) @@ -1653,6 +1698,7 @@ class QuotaReserveSqlAlchemyTestCase(test.TestCase): context = FakeContext('test_project', 'test_class') quotas = dict(volumes=5, gigabytes=10 * 1024, ) deltas = dict(volumes=2, gigabytes=2 * 1024, ) + self._stub_allocated_get_all_by_project() result = sqa_api.quota_reserve(context, self.resources, quotas, deltas, self.expire, 5, 0) @@ -1688,6 +1734,7 @@ class QuotaReserveSqlAlchemyTestCase(test.TestCase): context = FakeContext('test_project', 'test_class') quotas = dict(volumes=5, gigabytes=10 * 1024, ) deltas = dict(volumes=2, gigabytes=2 * 1024, ) + self._stub_allocated_get_all_by_project() result = sqa_api.quota_reserve(context, self.resources, quotas, deltas, self.expire, 0, max_age) @@ -1718,6 +1765,7 @@ class QuotaReserveSqlAlchemyTestCase(test.TestCase): context = FakeContext('test_project', 'test_class') quotas = dict(volumes=5, gigabytes=10 * 1024, ) deltas = dict(volumes=2, gigabytes=2 * 1024, ) + self._stub_allocated_get_all_by_project() result = sqa_api.quota_reserve(context, self.resources, quotas, deltas, self.expire, 0, 0) @@ -1748,6 +1796,7 @@ class QuotaReserveSqlAlchemyTestCase(test.TestCase): context = FakeContext('test_project', 'test_class') quotas = dict(volumes=5, gigabytes=10 * 1024, ) deltas = dict(volumes=-2, gigabytes=-2 * 1024, ) + self._stub_allocated_get_all_by_project() result = sqa_api.quota_reserve(context, self.resources, quotas, deltas, self.expire, 0, 0) @@ -1778,6 +1827,7 @@ class QuotaReserveSqlAlchemyTestCase(test.TestCase): context = FakeContext('test_project', 'test_class') quotas = dict(volumes=5, gigabytes=10 * 1024, ) deltas = dict(volumes=2, gigabytes=2 * 1024, ) + self._stub_allocated_get_all_by_project() self.assertRaises(exception.OverQuota, sqa_api.quota_reserve, context, self.resources, quotas, @@ -1803,6 +1853,7 @@ class QuotaReserveSqlAlchemyTestCase(test.TestCase): context = FakeContext('test_project', 'test_class') quotas = dict(volumes=5, gigabytes=10 * 1024, ) deltas = dict(volumes=-2, gigabytes=-2 * 1024, ) + self._stub_allocated_get_all_by_project() result = sqa_api.quota_reserve(context, self.resources, quotas, deltas, self.expire, 0, 0)