Implement "filter first" for identity panels

Implemented the "filter first" for the following identity panels:
- Users
- Groups
- Roles
- Projects

The functionality helps horizon not to hang and timeout when there is
a large set of identity resources to display. It can be turned on and
off easily.

In a subsequent patch set the same functionality will be added to
other identity views such as Project > Manage Members

Change-Id: I6e569712fb5159552a27271837cf2629059f5894
This commit is contained in:
Luis Daniel Castellanos 2017-01-11 15:03:37 -06:00
parent 590c3f0038
commit 33fcd95caf
10 changed files with 104 additions and 2 deletions

View File

@ -308,3 +308,10 @@ class GroupsViewTests(test.BaseAdminViewTests):
self.assertRedirectsNoFollow(res, GROUP_MANAGE_URL)
self.assertMessageCount(success=1)
@test.update_settings(FILTER_DATA_FIRST={'identity.groups': True})
def test_index_with_filter_first(self):
res = self.client.get(GROUPS_INDEX_URL)
self.assertTemplateUsed(res, constants.GROUPS_INDEX_VIEW_TEMPLATE)
groups = res.context['table'].data
self.assertItemsEqual(groups, [])

View File

@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
from django.conf import settings
from django.core.urlresolvers import reverse
from django.core.urlresolvers import reverse_lazy
from django.utils.translation import ugettext_lazy as _
@ -37,12 +38,28 @@ class IndexView(tables.DataTableView):
template_name = constants.GROUPS_INDEX_VIEW_TEMPLATE
page_title = _("Groups")
def needs_filter_first(self, table):
return self._needs_filter_first
def get_data(self):
groups = []
domain_id = api.keystone.get_effective_domain_id(self.request)
filters = self.get_filters()
self._needs_filter_first = False
if policy.check((("identity", "identity:list_groups"),),
self.request):
# If filter_first is set and if there are not other filters
# selected, then search criteria must be provided and
# return an empty list
filter_first = getattr(settings, 'FILTER_DATA_FIRST', {})
if filter_first.get('identity.groups', False) \
and len(filters) == 0:
self._needs_filter_first = True
return groups
domain_id = api.keystone.get_effective_domain_id(self.request)
try:
groups = api.keystone.group_list(self.request,
domain=domain_id,

View File

@ -97,6 +97,13 @@ class TenantsViewTests(test.BaseAdminViewTests):
self.assertItemsEqual(res.context['table'].data, domain_tenants)
self.assertContains(res, "<em>test_domain:</em>")
@test.update_settings(FILTER_DATA_FIRST={'identity.projects': True})
def test_index_with_filter_first(self):
res = self.client.get(INDEX_URL)
self.assertTemplateUsed(res, 'identity/projects/index.html')
projects = res.context['table'].data
self.assertItemsEqual(projects, [])
class ProjectsViewNonAdminTests(test.TestCase):
@override_settings(POLICY_CHECK_FUNCTION='openstack_auth.policy.check')

View File

@ -71,6 +71,9 @@ class IndexView(tables.DataTableView):
template_name = 'identity/projects/index.html'
page_title = _("Projects")
def needs_filter_first(self, table):
return self._needs_filter_first
def has_more_data(self, table):
return self._more
@ -80,8 +83,22 @@ class IndexView(tables.DataTableView):
project_tables.TenantsTable._meta.pagination_param, None)
self._more = False
filters = self.get_filters()
self._needs_filter_first = False
if policy.check((("identity", "identity:list_projects"),),
self.request):
# If filter_first is set and if there are not other filters
# selected, then search criteria must be provided and
# return an empty list
filter_first = getattr(settings, 'FILTER_DATA_FIRST', {})
if filter_first.get('identity.projects', False) and len(
filters) == 0:
self._needs_filter_first = True
self._more = False
return tenants
domain_context = api.keystone.get_effective_domain_id(self.request)
try:
tenants, self._more = api.keystone.tenant_list(

View File

@ -120,3 +120,10 @@ class RolesViewTests(test.BaseAdminViewTests):
res = self.client.post(ROLES_INDEX_URL, formData)
self.assertNoFormErrors(res)
@test.update_settings(FILTER_DATA_FIRST={'identity.roles': True})
def test_index_with_filter_first(self):
res = self.client.get(ROLES_INDEX_URL)
self.assertTemplateUsed(res, INDEX_TEMPLATE)
roles = res.context['table'].data
self.assertItemsEqual(roles, [])

View File

@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
from django.conf import settings
from django.core.urlresolvers import reverse
from django.core.urlresolvers import reverse_lazy
from django.utils.translation import ugettext_lazy as _
@ -35,11 +36,26 @@ class IndexView(tables.DataTableView):
table_class = project_tables.RolesTable
page_title = _("Roles")
def needs_filter_first(self, table):
return self._needs_filter_first
def get_data(self):
roles = []
filters = self.get_filters()
self._needs_filter_first = False
if policy.check((("identity", "identity:list_roles"),),
self.request):
# If filter_first is set and if there are not other filters
# selected, then search criteria must be provided
# and return an empty list
filter_first = getattr(settings, 'FILTER_DATA_FIRST', {})
if filter_first.get('identity.roles', False) and len(filters) == 0:
self._needs_filter_first = True
return roles
try:
roles = api.keystone.role_list(self.request,
filters=filters)

View File

@ -963,6 +963,13 @@ class UsersViewTests(test.BaseAdminViewTests):
self.assertNoFormErrors(res)
@test.update_settings(FILTER_DATA_FIRST={'identity.users': True})
def test_index_with_filter_first(self):
res = self.client.get(USERS_INDEX_URL)
self.assertTemplateUsed(res, 'identity/users/index.html')
users = res.context['table'].data
self.assertItemsEqual(users, [])
class SeleniumTests(test.SeleniumAdminTestCase):
def _get_default_domain(self):

View File

@ -49,11 +49,26 @@ class IndexView(tables.DataTableView):
template_name = 'identity/users/index.html'
page_title = _("Users")
def needs_filter_first(self, table):
return self._needs_filter_first
def get_data(self):
users = []
filters = self.get_filters()
self._needs_filter_first = False
if policy.check((("identity", "identity:list_users"),),
self.request):
# If filter_first is set and if there are not other filters
# selected, then search criteria must be provided
# and return an empty list
filter_first = getattr(settings, 'FILTER_DATA_FIRST', {})
if filter_first.get('identity.users', False) and len(filters) == 0:
self._needs_filter_first = True
return users
domain_context = api.keystone.get_effective_domain_id(self.request)
try:
users = api.keystone.user_list(self.request,

View File

@ -800,7 +800,11 @@ REST_API_REQUIRED_SETTINGS = ['OPENSTACK_HYPERVISOR_FEATURES',
# 'admin.images': False,
# 'admin.networks': False,
# 'admin.routers': False,
# 'admin.volumes': False
# 'admin.volumes': False,
# 'identity.users': False,
# 'identity.projects': False,
# 'identity.groups': False,
# 'identity.roles': False
#}
# Dict used to restrict user private subnet cidr range.

View File

@ -0,0 +1,5 @@
---
features:
- Implements the "filter first" functionality for identity panels
such as projects, users, groups and roles. The filter first
functionality is described in <https://blueprints.launchpad.net/horizon/+spec/admin-views-filter-first>`