From 98bb7bbb96b1e2c9f042c672a4f5a9af4236b4a8 Mon Sep 17 00:00:00 2001 From: Jake Yip Date: Wed, 31 Jul 2019 17:20:09 +1000 Subject: [PATCH] Return default quota from API Currently the dashboard and magnum clients are unable to get the default quota of a project, if a project does not have a quota set. This is due to the API returning a QuotaNotFound exception, rather than falling back to the default quota. The result is that dashboard is not displaying quotas correctly. It also means users are not able to see their default quota. This patch updates the API by returning the default quota instead of a QuotaNotFound exception. This makes magnum behave similarly to how other projects like designate handles quota. Story: 2006307 Task: 36029 Change-Id: I1b278d221d0f15d92d67869cd3ac897d041eaf90 --- magnum/api/controllers/v1/quota.py | 17 +++++++--- .../unit/api/controllers/v1/test_quota.py | 33 ++++++++++++++----- 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/magnum/api/controllers/v1/quota.py b/magnum/api/controllers/v1/quota.py index cdd0868aaf..7d3657f266 100644 --- a/magnum/api/controllers/v1/quota.py +++ b/magnum/api/controllers/v1/quota.py @@ -25,10 +25,13 @@ from magnum.api import utils as api_utils from magnum.api import validation from magnum.common import exception from magnum.common import policy +import magnum.conf from magnum.i18n import _ from magnum import objects from magnum.objects import fields +CONF = magnum.conf.CONF + class Quota(base.APIBase): """API representation of a project Quota. @@ -157,10 +160,16 @@ class QuotaController(base.Controller): if not context.is_admin and project_id != context.project_id: raise exception.NotAuthorized() - quota = objects.Quota.get_quota_by_project_id_resource(context, - project_id, - resource) - return Quota.convert(quota) + try: + quota = objects.Quota.get_quota_by_project_id_resource(context, + project_id, + resource) + quota = Quota.convert(quota) + except exception.QuotaNotFound: + # If explicit quota was not set for the project, use default limit + quota = Quota(project_id=project_id, + hard_limit=CONF.quotas.max_clusters_per_project) + return quota @expose.expose(Quota, body=Quota, status_code=201) @validation.enforce_valid_project_id_on_create() diff --git a/magnum/tests/unit/api/controllers/v1/test_quota.py b/magnum/tests/unit/api/controllers/v1/test_quota.py index 0fe1acd396..c62eaaaa2d 100644 --- a/magnum/tests/unit/api/controllers/v1/test_quota.py +++ b/magnum/tests/unit/api/controllers/v1/test_quota.py @@ -16,11 +16,14 @@ from keystoneauth1 import exceptions as ka_exception from magnum.api.controllers.v1 import quota as api_quota from magnum.common import clients +import magnum.conf from magnum.tests import base from magnum.tests.unit.api import base as api_base from magnum.tests.unit.api import utils as apiutils from magnum.tests.unit.objects import utils as obj_utils +CONF = magnum.conf.CONF + class TestQuotaObject(base.TestCase): def test_quota_init(self): @@ -60,14 +63,27 @@ class TestQuota(api_base.FunctionalTest): self.assertEqual(quota.resource, response['resource']) @mock.patch("magnum.common.policy.enforce") - def test_get_one_not_found(self, mock_policy): + def test_get_one_no_config_default(self, mock_policy): mock_policy.return_value = True response = self.get_json( - '/quotas/fake_project/invalid_res', + '/quotas/fake_project/Cluster', expect_errors=True) - self.assertEqual(404, response.status_int) - self.assertEqual('application/json', response.content_type) - self.assertTrue(response.json['errors']) + self.assertEqual(200, response.status_int) + self.assertEqual('fake_project', response.json['project_id']) + self.assertEqual(CONF.quotas.max_clusters_per_project, + response.json['hard_limit']) + + @mock.patch("magnum.common.policy.enforce") + def test_get_one_with_config_default(self, mock_policy): + mock_policy.return_value = True + quota = 15 + CONF.set_override('max_clusters_per_project', quota, group='quotas') + response = self.get_json( + '/quotas/fake_project/Cluster', + expect_errors=True) + self.assertEqual(200, response.status_int) + self.assertEqual('fake_project', response.json['project_id']) + self.assertEqual(quota, response.json['hard_limit']) def test_get_one_not_authorized(self): obj_utils.create_test_quota(self.context) @@ -300,6 +316,7 @@ class TestQuota(api_base.FunctionalTest): response = self.get_json( '/quotas/%s/%s' % (project_id, resource), expect_errors=True) - self.assertEqual(404, response.status_int) - self.assertEqual('application/json', response.content_type) - self.assertTrue(response.json['errors']) + self.assertEqual(200, response.status_int) + self.assertEqual('fake_project', response.json['project_id']) + self.assertEqual(CONF.quotas.max_clusters_per_project, + response.json['hard_limit'])