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
This commit is contained in:
wangxiyuan 2018-06-30 17:17:39 +08:00
parent 4b4835a01c
commit dca9a05c7c
6 changed files with 92 additions and 11 deletions

View File

@ -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()

View File

@ -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'],

View File

@ -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,

View File

@ -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

View File

@ -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.

View File

@ -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