Add include_limits filter
Add include_limits filter for get project to support fetching project hierarchy limits. This filter should be used together with "subtree_as_list" or "parents_as_list" filter bp: strict-two-level-model Change-Id: Ib602887c92b89be0ffec1394a3076f5dd5671511
This commit is contained in:
parent
059fa7eb83
commit
8038c70abf
|
@ -213,6 +213,8 @@ class ProjectV3(controller.V3Controller):
|
||||||
self.query_filter_is_true(params['subtree_as_list']))
|
self.query_filter_is_true(params['subtree_as_list']))
|
||||||
subtree_as_ids = 'subtree_as_ids' in params and (
|
subtree_as_ids = 'subtree_as_ids' in params and (
|
||||||
self.query_filter_is_true(params['subtree_as_ids']))
|
self.query_filter_is_true(params['subtree_as_ids']))
|
||||||
|
include_limits = 'include_limits' in params and (
|
||||||
|
self.query_filter_is_true(params['include_limits']))
|
||||||
|
|
||||||
# parents_as_list and parents_as_ids are mutually exclusive
|
# parents_as_list and parents_as_ids are mutually exclusive
|
||||||
if parents_as_list and parents_as_ids:
|
if parents_as_list and parents_as_ids:
|
||||||
|
@ -228,7 +230,7 @@ class ProjectV3(controller.V3Controller):
|
||||||
|
|
||||||
if parents_as_list:
|
if parents_as_list:
|
||||||
parents = PROVIDERS.resource_api.list_project_parents(
|
parents = PROVIDERS.resource_api.list_project_parents(
|
||||||
ref['id'], request.context.user_id)
|
ref['id'], request.context.user_id, include_limits)
|
||||||
ref['parents'] = [ProjectV3.wrap_member(context, p)
|
ref['parents'] = [ProjectV3.wrap_member(context, p)
|
||||||
for p in parents]
|
for p in parents]
|
||||||
elif parents_as_ids:
|
elif parents_as_ids:
|
||||||
|
@ -238,7 +240,7 @@ class ProjectV3(controller.V3Controller):
|
||||||
|
|
||||||
if subtree_as_list:
|
if subtree_as_list:
|
||||||
subtree = PROVIDERS.resource_api.list_projects_in_subtree(
|
subtree = PROVIDERS.resource_api.list_projects_in_subtree(
|
||||||
ref['id'], request.context.user_id)
|
ref['id'], request.context.user_id, include_limits)
|
||||||
ref['subtree'] = [ProjectV3.wrap_member(context, p)
|
ref['subtree'] = [ProjectV3.wrap_member(context, p)
|
||||||
for p in subtree]
|
for p in subtree]
|
||||||
elif subtree_as_ids:
|
elif subtree_as_ids:
|
||||||
|
|
|
@ -526,13 +526,28 @@ class Manager(manager.Manager):
|
||||||
# Check if project_id exists
|
# Check if project_id exists
|
||||||
self.get_project(project_id)
|
self.get_project(project_id)
|
||||||
|
|
||||||
def list_project_parents(self, project_id, user_id=None):
|
def _include_limits(self, projects):
|
||||||
|
"""Modify a list of projects to include limit information.
|
||||||
|
|
||||||
|
:param projects: a list of project references including an `id`
|
||||||
|
:type projects: list of dictionaries
|
||||||
|
"""
|
||||||
|
for project in projects:
|
||||||
|
hints = driver_hints.Hints()
|
||||||
|
hints.add_filter('project_id', project['id'])
|
||||||
|
limits = PROVIDERS.unified_limit_api.list_limits(hints)
|
||||||
|
project['limits'] = limits
|
||||||
|
|
||||||
|
def list_project_parents(self, project_id, user_id=None,
|
||||||
|
include_limits=False):
|
||||||
self._assert_valid_project_id(project_id)
|
self._assert_valid_project_id(project_id)
|
||||||
parents = self.driver.list_project_parents(project_id)
|
parents = self.driver.list_project_parents(project_id)
|
||||||
# If a user_id was provided, the returned list should be filtered
|
# If a user_id was provided, the returned list should be filtered
|
||||||
# against the projects this user has access to.
|
# against the projects this user has access to.
|
||||||
if user_id:
|
if user_id:
|
||||||
parents = self._filter_projects_list(parents, user_id)
|
parents = self._filter_projects_list(parents, user_id)
|
||||||
|
if include_limits:
|
||||||
|
self._include_limits(parents)
|
||||||
return parents
|
return parents
|
||||||
|
|
||||||
def _build_parents_as_ids_dict(self, project, parents_by_id):
|
def _build_parents_as_ids_dict(self, project, parents_by_id):
|
||||||
|
@ -578,13 +593,16 @@ class Manager(manager.Manager):
|
||||||
project, {proj['id']: proj for proj in parents_list})
|
project, {proj['id']: proj for proj in parents_list})
|
||||||
return parents_as_ids
|
return parents_as_ids
|
||||||
|
|
||||||
def list_projects_in_subtree(self, project_id, user_id=None):
|
def list_projects_in_subtree(self, project_id, user_id=None,
|
||||||
|
include_limits=False):
|
||||||
self._assert_valid_project_id(project_id)
|
self._assert_valid_project_id(project_id)
|
||||||
subtree = self.driver.list_projects_in_subtree(project_id)
|
subtree = self.driver.list_projects_in_subtree(project_id)
|
||||||
# If a user_id was provided, the returned list should be filtered
|
# If a user_id was provided, the returned list should be filtered
|
||||||
# against the projects this user has access to.
|
# against the projects this user has access to.
|
||||||
if user_id:
|
if user_id:
|
||||||
subtree = self._filter_projects_list(subtree, user_id)
|
subtree = self._filter_projects_list(subtree, user_id)
|
||||||
|
if include_limits:
|
||||||
|
self._include_limits(subtree)
|
||||||
return subtree
|
return subtree
|
||||||
|
|
||||||
def _build_subtree_as_ids_dict(self, project_id, subtree_by_parent):
|
def _build_subtree_as_ids_dict(self, project_id, subtree_by_parent):
|
||||||
|
|
|
@ -1090,6 +1090,70 @@ class ResourceTestCase(test_v3.RestfulTestCase,
|
||||||
'project_id': projects[1]['project']['id']},
|
'project_id': projects[1]['project']['id']},
|
||||||
expected_status=http_client.BAD_REQUEST)
|
expected_status=http_client.BAD_REQUEST)
|
||||||
|
|
||||||
|
def test_get_project_with_include_limits(self):
|
||||||
|
parent, project, subproject = self._create_projects_hierarchy(2)
|
||||||
|
# Assign a role for the user on all the created projects
|
||||||
|
for proj in (parent, project, subproject):
|
||||||
|
self.put(self.build_role_assignment_link(
|
||||||
|
role_id=self.role_id, user_id=self.user_id,
|
||||||
|
project_id=proj['project']['id']))
|
||||||
|
# create a registered limit and three limits for each project.
|
||||||
|
reg_limit = unit.new_registered_limit_ref(service_id=self.service_id,
|
||||||
|
region_id=self.region_id,
|
||||||
|
resource_name='volume')
|
||||||
|
self.post(
|
||||||
|
'/registered_limits',
|
||||||
|
body={'registered_limits': [reg_limit]},
|
||||||
|
expected_status=http_client.CREATED)
|
||||||
|
limit1 = unit.new_limit_ref(project_id=parent['project']['id'],
|
||||||
|
service_id=self.service_id,
|
||||||
|
region_id=self.region_id,
|
||||||
|
resource_name='volume')
|
||||||
|
limit2 = unit.new_limit_ref(project_id=project['project']['id'],
|
||||||
|
service_id=self.service_id,
|
||||||
|
region_id=self.region_id,
|
||||||
|
resource_name='volume')
|
||||||
|
limit3 = unit.new_limit_ref(project_id=subproject['project']['id'],
|
||||||
|
service_id=self.service_id,
|
||||||
|
region_id=self.region_id,
|
||||||
|
resource_name='volume')
|
||||||
|
self.post(
|
||||||
|
'/limits',
|
||||||
|
body={'limits': [limit1, limit2, limit3]},
|
||||||
|
expected_status=http_client.CREATED)
|
||||||
|
# "include_limits" should work together with "parents_as_list" or
|
||||||
|
# "subtree_as_list". Only using "include_limits" really does nothing.
|
||||||
|
r = self.get('/projects/%(project_id)s?include_limits' %
|
||||||
|
{'project_id': subproject['project']['id']})
|
||||||
|
|
||||||
|
self.assertIsNone(r.result['project'].get('parents'))
|
||||||
|
self.assertIsNone(r.result['project'].get('subtree'))
|
||||||
|
self.assertIsNone(r.result['project'].get('limits'))
|
||||||
|
|
||||||
|
# using "include_limits" with "parents_as_list"
|
||||||
|
r = self.get('/projects/%(project_id)s?include_limits&parents_as_list'
|
||||||
|
% {'project_id': subproject['project']['id']})
|
||||||
|
|
||||||
|
self.assertEqual(2, len(r.result['project']['parents']))
|
||||||
|
for parent in r.result['project']['parents']:
|
||||||
|
self.assertEqual(1, len(parent['project']['limits']))
|
||||||
|
self.assertEqual(parent['project']['id'],
|
||||||
|
parent['project']['limits'][0]['project_id'])
|
||||||
|
self.assertEqual(10,
|
||||||
|
parent['project']['limits'][0]['resource_limit'])
|
||||||
|
|
||||||
|
# using "include_limits" with "subtree_as_list"
|
||||||
|
r = self.get('/projects/%(project_id)s?include_limits&subtree_as_list'
|
||||||
|
% {'project_id': parent['project']['id']})
|
||||||
|
|
||||||
|
self.assertEqual(2, len(r.result['project']['subtree']))
|
||||||
|
for child in r.result['project']['subtree']:
|
||||||
|
self.assertEqual(1, len(child['project']['limits']))
|
||||||
|
self.assertEqual(child['project']['id'],
|
||||||
|
child['project']['limits'][0]['project_id'])
|
||||||
|
self.assertEqual(10,
|
||||||
|
child['project']['limits'][0]['resource_limit'])
|
||||||
|
|
||||||
def test_list_project_is_domain_filter(self):
|
def test_list_project_is_domain_filter(self):
|
||||||
"""Call ``GET /projects?is_domain=True/False``."""
|
"""Call ``GET /projects?is_domain=True/False``."""
|
||||||
# Get the initial number of projects, both acting as a domain as well
|
# Get the initial number of projects, both acting as a domain as well
|
||||||
|
|
|
@ -19,3 +19,10 @@ features:
|
||||||
The `project_id` filter is added for listing limits. This filter is used
|
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
|
for system-scoped request only to fetch the specified project limits. Non
|
||||||
system-scoped request will get empty response body instead.
|
system-scoped request will get empty response body instead.
|
||||||
|
|
||||||
|
- >
|
||||||
|
[`blueprint strict-two-level-model <https://blueprints.launchpad.net/keystone/+spec/strict-two-level-model>`_]
|
||||||
|
The `include_limits` filter is added to `GET /v3/projects/{project_id}` API.
|
||||||
|
This filter should be used together with `parents_as_list` or
|
||||||
|
`subtree_as_list` filter to add parent/sub project's limit information the
|
||||||
|
response body.
|
||||||
|
|
Loading…
Reference in New Issue