diff options
author | wangxiyuan <wangxiyuan@huawei.com> | 2018-06-30 17:17:39 +0800 |
---|---|---|
committer | wangxiyuan <wangxiyuan@huawei.com> | 2018-07-17 12:00:08 +0800 |
commit | dca9a05c7c86f1b32becd0dfae05c44f00ea6d95 (patch) | |
tree | 5ea5369ffbd058f860c2445856ee8b875f3a21c1 | |
parent | 4b4835a01c662ddb11e9f1aace47a02c6e337978 (diff) | |
download | keystone-dca9a05c7c86f1b32becd0dfae05c44f00ea6d95.tar.gz |
Add project_id filter for listing limit
Add project_id filter for listing limit. This filter
can be only used by system-scoped request to fetch the
specified project's limits.
bp: strict-two-level-model
Change-Id: I1b8cc227ed0710702aa099f09821f6eb897bb32c
-rw-r--r-- | keystone/limit/controllers.py | 15 | ||||
-rw-r--r-- | keystone/tests/unit/limit/test_backends.py | 10 | ||||
-rw-r--r-- | keystone/tests/unit/test_limits.py | 68 | ||||
-rw-r--r-- | lower-constraints.txt | 2 | ||||
-rw-r--r-- | releasenotes/notes/bp-strict-two-level-model.yaml | 6 | ||||
-rw-r--r-- | requirements.txt | 2 |
6 files changed, 92 insertions, 11 deletions
diff --git a/keystone/limit/controllers.py b/keystone/limit/controllers.py index 440b55f94..a17bc865a 100644 --- a/keystone/limit/controllers.py +++ b/keystone/limit/controllers.py @@ -101,17 +101,22 @@ class LimitV3(controller.V3Controller): limit_id, limit) return LimitV3.wrap_member(request.context_dict, ref) - @controller.filterprotected('service_id', 'region_id', 'resource_name') + @controller.filterprotected('service_id', 'region_id', 'resource_name', + 'project_id') def list_limits(self, request, filters): hints = LimitV3.build_driver_hints(request, filters) - # TODO(wxy): Add system-scope check. If the request is system-scoped, - # it can get all limits. context = request.context - if not context.is_admin and not ('admin' in context.roles): + project_id_filter = hints.get_exact_filter_by_name('project_id') + if project_id_filter: + if context.system_scope: + refs = PROVIDERS.unified_limit_api.list_limits(hints) + else: + refs = [] + else: project_id = context.project_id if project_id: hints.add_filter('project_id', project_id) - refs = PROVIDERS.unified_limit_api.list_limits(hints) + refs = PROVIDERS.unified_limit_api.list_limits(hints) return LimitV3.wrap_collection(request.context_dict, refs, hints=hints) @controller.protected() diff --git a/keystone/tests/unit/limit/test_backends.py b/keystone/tests/unit/limit/test_backends.py index e971ff7a2..78dd8d7d7 100644 --- a/keystone/tests/unit/limit/test_backends.py +++ b/keystone/tests/unit/limit/test_backends.py @@ -589,7 +589,7 @@ class LimitTests(object): region_id=self.region_one['id'], resource_name='volume', resource_limit=10, id=uuid.uuid4().hex) limit_2 = unit.new_limit_ref( - project_id=self.tenant_bar['id'], + project_id=self.tenant_baz['id'], service_id=self.service_one['id'], region_id=self.region_two['id'], resource_name='snapshot', resource_limit=10, id=uuid.uuid4().hex) @@ -597,23 +597,25 @@ class LimitTests(object): hints = driver_hints.Hints() hints.add_filter('service_id', self.service_one['id']) - hints.add_filter('project_id', self.tenant_bar['id']) res = PROVIDERS.unified_limit_api.list_limits(hints) self.assertEqual(2, len(res)) hints = driver_hints.Hints() hints.add_filter('region_id', self.region_one['id']) - hints.add_filter('project_id', self.tenant_bar['id']) res = PROVIDERS.unified_limit_api.list_limits(hints) self.assertEqual(1, len(res)) self.assertDictEqual(limit_1, res[0]) hints = driver_hints.Hints() hints.add_filter('resource_name', 'backup') - hints.add_filter('project_id', self.tenant_bar['id']) res = PROVIDERS.unified_limit_api.list_limits(hints) self.assertEqual(0, len(res)) + hints = driver_hints.Hints() + hints.add_filter('project_id', self.tenant_bar['id']) + res = PROVIDERS.unified_limit_api.list_limits(hints) + self.assertEqual(1, len(res)) + def test_list_limit_by_multi_filter_with_project_id(self): limit_1 = unit.new_limit_ref( project_id=self.tenant_bar['id'], diff --git a/keystone/tests/unit/test_limits.py b/keystone/tests/unit/test_limits.py index ff6d2f1a8..03903f3c1 100644 --- a/keystone/tests/unit/test_limits.py +++ b/keystone/tests/unit/test_limits.py @@ -726,6 +726,74 @@ class LimitsTestCase(test_v3.RestfulTestCase): 'resource_limit']: self.assertEqual(limits[0][key], ref1[key]) + def test_list_limit_with_project_id_filter(self): + # Create a new projects and a 'non-admin' role for test. The assignment + # is like: + # + # self.user -- admin -- self.project (default) + # self.user -- non-admin -- the new project + # self.user -- admin -- system + project_2 = unit.new_project_ref(domain_id=self.domain_id) + project_2_id = project_2['id'] + PROVIDERS.resource_api.create_project(project_2_id, project_2) + + role_2 = unit.new_role_ref(name='non-admin') + role_2_id = role_2['id'] + PROVIDERS.role_api.create_role(role_2_id, role_2) + + PROVIDERS.assignment_api.add_role_to_user_and_project( + self.user_id, project_2_id, role_2_id) + PROVIDERS.assignment_api.create_system_grant_for_user( + self.user_id, self.role['id']) + + # create two limit in different projects for test. + ref1 = unit.new_limit_ref(project_id=self.project_id, + service_id=self.service_id, + region_id=self.region_id, + resource_name='volume') + ref2 = unit.new_limit_ref(project_id=project_2_id, + service_id=self.service_id2, + resource_name='snapshot') + self.post( + '/limits', + body={'limits': [ref1, ref2]}, + expected_status=http_client.CREATED) + + # non system scoped request will get the limits in its project. + r = self.get('/limits', expected_status=http_client.OK) + limits = r.result['limits'] + self.assertEqual(1, len(limits)) + self.assertEqual(self.project_id, limits[0]['project_id']) + + r = self.get( + '/limits', expected_status=http_client.OK, + auth=self.build_authentication_request( + user_id=self.user['id'], password=self.user['password'], + project_id=project_2_id)) + limits = r.result['limits'] + self.assertEqual(1, len(limits)) + self.assertEqual(project_2_id, limits[0]['project_id']) + + # if non system scoped request contain project_id filter, keystone + # will return an empty list. + r = self.get( + '/limits?project_id=%s' % self.project_id, + expected_status=http_client.OK) + limits = r.result['limits'] + self.assertEqual(0, len(limits)) + + # a system scoped request can specify the project_id filter + r = self.get( + '/limits?project_id=%s' % self.project_id, + expected_status=http_client.OK, + auth=self.build_authentication_request( + user_id=self.user['id'], password=self.user['password'], + system=True) + ) + limits = r.result['limits'] + self.assertEqual(1, len(limits)) + self.assertEqual(self.project_id, limits[0]['project_id']) + def test_show_limit(self): ref1 = unit.new_limit_ref(project_id=self.project_id, service_id=self.service_id, diff --git a/lower-constraints.txt b/lower-constraints.txt index 5b46d81a4..92633b5d6 100644 --- a/lower-constraints.txt +++ b/lower-constraints.txt @@ -63,7 +63,7 @@ os-testr==1.0.0 oslo.cache==1.26.0 oslo.concurrency==3.26.0 oslo.config==5.2.0 -oslo.context==2.19.2 +oslo.context==2.21.0 oslo.db==4.27.0 oslo.i18n==3.15.3 oslo.log==3.36.0 diff --git a/releasenotes/notes/bp-strict-two-level-model.yaml b/releasenotes/notes/bp-strict-two-level-model.yaml index 964fa4ad8..7af8c551b 100644 --- a/releasenotes/notes/bp-strict-two-level-model.yaml +++ b/releasenotes/notes/bp-strict-two-level-model.yaml @@ -13,3 +13,9 @@ features: Please ensure that the previous project and limit structure deployment in your Keystone won't break this model before starting to use it. + + - > + [`blueprint strict-two-level-model <https://blueprints.launchpad.net/keystone/+spec/strict-two-level-model>`_] + The `project_id` filter is added for listing limits. This filter is used + for system-scoped request only to fetch the specified project limits. Non + system-scoped request will get empty response body instead. diff --git a/requirements.txt b/requirements.txt index 83ad7ef5e..4ad163089 100644 --- a/requirements.txt +++ b/requirements.txt @@ -24,7 +24,7 @@ scrypt>=0.8.0 # BSD oslo.cache>=1.26.0 # Apache-2.0 oslo.concurrency>=3.26.0 # Apache-2.0 oslo.config>=5.2.0 # Apache-2.0 -oslo.context>=2.19.2 # Apache-2.0 +oslo.context>=2.21.0 # Apache-2.0 oslo.messaging>=5.29.0 # Apache-2.0 oslo.db>=4.27.0 # Apache-2.0 oslo.i18n>=3.15.3 # Apache-2.0 |