diff options
author | Lingxian Kong <anlin.kong@gmail.com> | 2021-08-25 16:11:12 +1200 |
---|---|---|
committer | Lingxian Kong <anlin.kong@gmail.com> | 2021-08-25 17:14:42 +1200 |
commit | f3459e2662e86b275ac3baf01330753df4d3f092 (patch) | |
tree | ea2491dc8319e77a3a38bf60e1830cd9bca1a9e0 | |
parent | c3a8930eb152072ab71ccc6033862b3ec45f5e4f (diff) | |
download | trove-f3459e2662e86b275ac3baf01330753df4d3f092.tar.gz |
Allow regular user to get quotas16.0.0.0rc116.0.0
The project user can query the project's own resource quota.
Story: 2009140
Task: 43082
Change-Id: Iebac740e982a89fcf882a2cfc3e447ac53ee6656
-rw-r--r-- | api-ref/source/quotas.inc | 3 | ||||
-rw-r--r-- | releasenotes/notes/xena-allow-project-show-resource-quota.yaml | 3 | ||||
-rw-r--r-- | trove/common/wsgi.py | 1 | ||||
-rw-r--r-- | trove/extensions/mgmt/quota/service.py | 13 | ||||
-rw-r--r-- | trove/tests/unittests/extensions/mgmt/quota/__init__.py | 0 | ||||
-rw-r--r-- | trove/tests/unittests/extensions/mgmt/quota/test_service.py | 81 |
6 files changed, 98 insertions, 3 deletions
diff --git a/api-ref/source/quotas.inc b/api-ref/source/quotas.inc index 52b86a76..f70756f9 100644 --- a/api-ref/source/quotas.inc +++ b/api-ref/source/quotas.inc @@ -38,7 +38,8 @@ Show resources quota for a specific project .. rest_method:: GET /v1.0/{project_id}/mgmt/quotas/{user_project} -Admin only action by default. +Admin can query resource quota of any project. The project user can only show +the project's own quota. Normal response codes: 200 diff --git a/releasenotes/notes/xena-allow-project-show-resource-quota.yaml b/releasenotes/notes/xena-allow-project-show-resource-quota.yaml new file mode 100644 index 00000000..ba0ebe61 --- /dev/null +++ b/releasenotes/notes/xena-allow-project-show-resource-quota.yaml @@ -0,0 +1,3 @@ +--- +features: + - The project user can query the project's own resource quota. diff --git a/trove/common/wsgi.py b/trove/common/wsgi.py index 4c8673d5..66cff129 100644 --- a/trove/common/wsgi.py +++ b/trove/common/wsgi.py @@ -324,6 +324,7 @@ class Controller(object): exception.ModuleAppliedToInstance, exception.PolicyNotAuthorized, exception.LogAccessForbidden, + exception.TroveOperationAuthError, ], webob.exc.HTTPBadRequest: [ exception.InvalidModelError, diff --git a/trove/extensions/mgmt/quota/service.py b/trove/extensions/mgmt/quota/service.py index a16f8716..bb55e781 100644 --- a/trove/extensions/mgmt/quota/service.py +++ b/trove/extensions/mgmt/quota/service.py @@ -29,12 +29,21 @@ LOG = logging.getLogger(__name__) class QuotaController(wsgi.Controller): """Controller for quota functionality.""" - @admin_context def show(self, req, tenant_id, id): - """Return all quotas for this tenant.""" + """Return all quotas for this tenant. + + Regular tenant can get his own resource quota. + Admin user can get quota for any tenant. + """ LOG.info("Indexing quota info for tenant '%(id)s'\n" "req : '%(req)s'\n\n", {"id": id, "req": req}) + context = req.environ[wsgi.CONTEXT_KEY] + if id != tenant_id and not context.is_admin: + raise exception.TroveOperationAuthError( + tenant_id=tenant_id + ) + usages = quota_engine.get_all_quota_usages_by_tenant(id) limits = quota_engine.get_all_quotas_by_tenant(id) for key in usages.keys(): diff --git a/trove/tests/unittests/extensions/mgmt/quota/__init__.py b/trove/tests/unittests/extensions/mgmt/quota/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/trove/tests/unittests/extensions/mgmt/quota/__init__.py diff --git a/trove/tests/unittests/extensions/mgmt/quota/test_service.py b/trove/tests/unittests/extensions/mgmt/quota/test_service.py new file mode 100644 index 00000000..5c853255 --- /dev/null +++ b/trove/tests/unittests/extensions/mgmt/quota/test_service.py @@ -0,0 +1,81 @@ +# Copyright 2021 Catalyst Cloud +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from unittest import mock + +from trove.common import exception +from trove.common import wsgi +from trove.extensions.mgmt.quota import service as quota_service +from trove.tests.unittests import trove_testtools +from trove.tests.unittests.util import util + + +class TestQuotaController(trove_testtools.TestCase): + @classmethod + def setUpClass(cls): + util.init_db() + cls.controller = quota_service.QuotaController() + cls.admin_project_id = cls.random_uuid() + super(TestQuotaController, cls).setUpClass() + + @classmethod + def tearDownClass(cls): + util.cleanup_db() + super(TestQuotaController, cls).tearDownClass() + + def test_show_admin_query(self): + user_project_id = self.random_uuid() + req_mock = mock.MagicMock( + environ={ + wsgi.CONTEXT_KEY: mock.MagicMock( + project_id=self.admin_project_id, + is_admin=True + ) + } + ) + result = self.controller.show(req_mock, self.admin_project_id, + user_project_id) + + self.assertEqual(200, result.status) + + def test_show_user_query(self): + """Show the tenant's own quota.""" + user_project_id = self.random_uuid() + req_mock = mock.MagicMock( + environ={ + wsgi.CONTEXT_KEY: mock.MagicMock( + is_admin=False + ) + } + ) + result = self.controller.show(req_mock, user_project_id, + user_project_id) + + self.assertEqual(200, result.status) + + def test_show_user_query_not_allowed(self): + """Show other tenant's quota should fail.""" + user_project_id = self.random_uuid() + req_mock = mock.MagicMock( + environ={ + wsgi.CONTEXT_KEY: mock.MagicMock( + is_admin=False + ) + } + ) + self.assertRaises( + exception.TroveOperationAuthError, + self.controller.show, + req_mock, user_project_id, + self.random_uuid() + ) |