Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RHCLOUD-36102] - Slow loading of data from roles endpoint perfo… #1354

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
710ff4b
[WIP][RHCLOUD-36102] - Slow loading of data from roles endpoint perfo…
EvanCasey13 Nov 29, 2024
3cd7d46
Roles filtering refactor
EvanCasey13 Dec 2, 2024
6849d7b
Roles endpoint filtering continued
EvanCasey13 Dec 3, 2024
cd1dbf0
Roles endpoint filtering - username query parameter handling
EvanCasey13 Dec 4, 2024
2c1caac
Roles endpoint - filtering addition complete
EvanCasey13 Dec 5, 2024
82f2c76
remove print statement from roles test
EvanCasey13 Dec 5, 2024
a221512
Roles endpoint filtering performance done
EvanCasey13 Dec 6, 2024
a49dc74
Pagination readded to roles endpoint
EvanCasey13 Dec 9, 2024
0c72049
Added prefetch_related to base_queryset for access and ext_relations
EvanCasey13 Dec 10, 2024
023ff1b
lint fix
EvanCasey13 Dec 10, 2024
6816159
Removed group_in and group_in_counts from role serializer, will add d…
EvanCasey13 Dec 11, 2024
3bc8ed4
added dynamic annotation and changed role serializer to groups_in field
EvanCasey13 Dec 19, 2024
4e6b58f
Changed to use get_role_queryset from querysets to handle scope/admin…
EvanCasey13 Jan 9, 2025
3d75490
Merge branch 'master' into role_endpoint_performance_improvements
EvanCasey13 Jan 9, 2025
7cce7af
role query reduction from 33 to 24 queries
EvanCasey13 Jan 14, 2025
eeb98de
reduction from to 6 queries for a request for roles endpoint from 33 …
EvanCasey13 Jan 14, 2025
b5a9c74
Merge branch 'master' into role_endpoint_performance_improvements
EvanCasey13 Jan 14, 2025
b8ef8fe
remove redundant default limit for common pagination#
EvanCasey13 Jan 14, 2025
0d9f7e5
Merge branch 'master' into role_endpoint_performance_improvements
EvanCasey13 Jan 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 4 additions & 15 deletions rbac/management/role/serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ class RoleSerializer(serializers.ModelSerializer):
access = AccessSerializer(many=True)
policyCount = serializers.IntegerField(read_only=True)
accessCount = serializers.IntegerField(read_only=True)
groups_in_count = serializers.IntegerField(read_only=True)
groups_in = serializers.ListField(read_only=True)
applications = serializers.SerializerMethodField()
system = serializers.BooleanField(read_only=True)
platform_default = serializers.BooleanField(read_only=True)
Expand All @@ -100,8 +102,6 @@ class RoleSerializer(serializers.ModelSerializer):
modified = serializers.DateTimeField(read_only=True)
external_role_id = serializers.SerializerMethodField()
external_tenant = serializers.SerializerMethodField()
groups_in_count = serializers.SerializerMethodField()
groups_in = serializers.SerializerMethodField()

class Meta:
"""Metadata for the serializer."""
Expand All @@ -115,6 +115,8 @@ class Meta:
"access",
"policyCount",
"accessCount",
"groups_in_count",
"groups_in",
"applications",
"system",
"platform_default",
Expand All @@ -123,8 +125,6 @@ class Meta:
"modified",
"external_role_id",
"external_tenant",
"groups_in_count",
"groups_in",
)

def get_applications(self, obj):
Expand Down Expand Up @@ -165,17 +165,6 @@ def get_external_tenant(self, obj):
"""Get the external tenant name if it's from an external tenant."""
return obj.external_tenant_name()

def get_groups_in_count(self, obj):
"""Get the total count of groups where the role is in."""
request = self.context.get("request")
groups_in = obtain_groups_in(obj, request)
return groups_in.count() # Make sure this returns an integer count

def get_groups_in(self, obj):
"""Get the groups where the role is in."""
request = self.context.get("request")
return obtain_groups_in(obj, request).values("name", "uuid", "description")


class RoleMinimumSerializer(SerializerCreateOverrideMixin, serializers.ModelSerializer):
"""Serializer for the Role model that doesn't return access info."""
Expand Down
27 changes: 20 additions & 7 deletions rbac/management/role/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,12 +329,6 @@ def list(self, request, *args, **kwargs):

"""
public_tenant = Tenant.objects.get(tenant_name="public")
EvanCasey13 marked this conversation as resolved.
Show resolved Hide resolved
base_queryset = (
Role.objects.prefetch_related("access", "ext_relation")
.filter(tenant__in=[request.tenant, public_tenant])
.annotate(policyCount=Count("policies", distinct=True), accessCount=Count("access", distinct=True))
)

# Filtering
query_params = {
"external_tenant": request.query_params.get("external_tenant", None),
Expand All @@ -349,8 +343,27 @@ def list(self, request, *args, **kwargs):
"username": request.query_params.get("username", None),
"limit": request.query_params.get("limit", 10),
"offset": request.query_params.get("offset", 0),
"add_fields": request.query_params.get("add_fields", None),
"add_fields": request.query_params.get("add_fields", ""),
}
add_fields = query_params["add_fields"]
add_fields_split = add_fields.split(",")

base_queryset = (
Role.objects.prefetch_related("access", "ext_relation")
.filter(tenant__in=[request.tenant, public_tenant])
.annotate(
policyCount=Count("policies", distinct=True),
accessCount=Count("access", distinct=True),
)
)

# Dynamic annotations
if "groups_in_count" in add_fields_split:
EvanCasey13 marked this conversation as resolved.
Show resolved Hide resolved
base_queryset = base_queryset.annotate(groups_in_count=Count("policies__group"))
elif "groups_in" in add_fields_split:
base_queryset = base_queryset.annotate(groups_in=F("policies__group__name"))
else:
base_queryset = base_queryset

filters = []
limit = query_params["limit"]
Expand Down
9 changes: 4 additions & 5 deletions tests/management/role/test_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,16 +151,14 @@ def setUp(self):
"display_name",
"system",
"created",
"access",
"policyCount",
"accessCount",
"modified",
"platform_default",
"admin_default",
"external_role_id",
"external_tenant",
"groups_in_count",
"groups_in",
"access",
}

self.principal = Principal(username=self.user_data["username"], tenant=self.tenant)
Expand Down Expand Up @@ -914,7 +912,7 @@ def test_list_role_with_groups_in_fields_with_username_param_for_non_org_admin(s
# make sure all roles are from:
# * custom group 'NewGroupForJohn' or
# * 'Default access' group
groups = [default_access_group_name, custom_group_name, default_admin_access_group_name]
groups = [default_access_group_name, custom_group_name]
for role in response_data:
for group in role[groups_in]:
self.assertIn(group["name"], groups)
Expand Down Expand Up @@ -1118,6 +1116,7 @@ def test_list_role_with_groups_in_fields_for_admin_scope_success(self):

response_data = response.data.get("data")
for iterRole in response_data:
print(iterRole.get("groups_in"))
EvanCasey13 marked this conversation as resolved.
Show resolved Hide resolved
# fields displayed are same as defined, groupsInCount is added
self.assertEqual(new_display_fields, set(iterRole.keys()))
self.assertIsNotNone(iterRole.get("groups_in")[0]["name"])
Expand Down Expand Up @@ -1210,7 +1209,7 @@ def test_list_role_with_additional_fields_principal_success(self):
self.assertEqual(len(response.data.get("data")), 5)

role = response.data.get("data")[0]

EvanCasey13 marked this conversation as resolved.
Show resolved Hide resolved
print(role)
self.assertEqual(new_display_fields, set(role.keys()))
self.assertEqual(role["groups_in_count"], 1)

Expand Down
Loading