Skip to content

Commit 98b6da9

Browse files
committed
Warm cache and crawl full graph
1 parent 97b38c0 commit 98b6da9

File tree

4 files changed

+40
-10
lines changed

4 files changed

+40
-10
lines changed

ansible_base/rbac/models/content_type.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,14 @@ def load_remote_types(self, remote_data: list[dict]):
188188
ct.parent_content_type = DABContentType.objects.get(api_slug=pct_slug)
189189
ct.save()
190190

191+
def warm_cache(self, queryset=None):
192+
"Put objects from the given queryset into the cache, or all objects"
193+
if queryset is None:
194+
queryset = self.all()
195+
196+
for ct in queryset:
197+
self._add_to_cache(self.db, ct)
198+
191199

192200
class DABContentType(django_models.Model):
193201
"""Like Django ContentType model but scoped by service."""

ansible_base/rbac/validators.py

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,26 @@ def permissions_allowed_for_system_role() -> dict[Type[Model], list[str]]:
5656
return permissions_by_model
5757

5858

59+
def get_descendent_models_from_db(main_ct: Model):
60+
"""For a given content type, get all content types from the database that reference them as a parent
61+
62+
Including any content types that reference a content type that reference this content type as a parent.
63+
"""
64+
seen_ids = set()
65+
result = []
66+
queue = [main_ct]
67+
68+
while queue:
69+
current = queue.pop(0)
70+
for child in current.child_content_types.all():
71+
if child.pk not in seen_ids:
72+
seen_ids.add(child.pk)
73+
result.append(child)
74+
queue.append(child)
75+
76+
return result
77+
78+
5979
def permissions_allowed_for_role(cls) -> dict[Union[Type[Model], Type[RemoteObject]], list[str]]:
6080
"Permission codenames valid for a RoleDefinition of given class, organized by permission class"
6181
if cls is None:
@@ -66,19 +86,21 @@ def permissions_allowed_for_role(cls) -> dict[Union[Type[Model], Type[RemoteObje
6686

6787
permissions_by_model = defaultdict(list)
6888

89+
# Warm cache to load all types and related permissions
90+
permission_registry.content_type_model.objects.warm_cache(permission_registry.content_type_model.objects.prefetch_related('dab_permissions'))
91+
92+
# Add direct model permissions
6993
cls_ct = permission_registry.content_type_model.objects.get_for_model(cls)
7094
for permission in cls_ct.dab_permissions.all():
7195
if not is_add_perm(permission.codename):
7296
permissions_by_model[cls].append(permission.codename)
7397

7498
# Add permissions for all child types
75-
for ct in cls_ct.child_content_types.prefetch_related('dab_permissions'):
76-
for permission in ct.dab_permissions.prefetch_related('content_type__child_content_types'):
77-
permissions_by_model[ct.model_class()].append(permission.codename)
78-
# Process grandchild models
79-
for grandchild_ct in permission.content_type.child_content_types.all():
80-
for grandchild_perm in grandchild_ct.dab_permissions.all():
81-
permissions_by_model[grandchild_ct.model_class()].append(grandchild_perm.codename)
99+
for ct in get_descendent_models_from_db(cls_ct):
100+
for child_permission in ct.dab_permissions.all():
101+
# Include add permissions for child models
102+
permissions_by_model[ct.model_class()].append(child_permission.codename)
103+
82104
return permissions_by_model
83105

84106

test_app/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ class ManualExtraUUIDModel(models.Model):
269269
"""Extra-uniquene UUID made by manually feeding in a prior UUIDModel
270270
271271
An example would be:
272-
ManualExtraUUIDModel.objects.create(organization=org)
272+
ManualExtraUUIDModel.objects.create(uuidmodel_ptr=AutoExtraUUIDModel.objects.create(organization=org))
273273
"""
274274

275275
uuidmodel_ptr = models.OneToOneField(UUIDModel, on_delete=models.CASCADE, editable=False, related_name="+", primary_key=True)

test_app/tests/rbac/remote/test_service_api.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,11 @@ def test_apply_role_assignment(admin_api_client, rando, inv_rd, inventory):
128128
assert not rando.has_obj_perm(inventory, 'change')
129129
response = admin_api_client.post(url, data=data)
130130
assert response.status_code == 201, response.data
131-
assert not rando.has_obj_perm(inventory, 'change')
131+
assert rando.has_obj_perm(inventory, 'change')
132132

133133
# Second try, response code indicates assignment already exists
134134
response = admin_api_client.post(url, data=data)
135-
assert response.status_code == 409, response.data
135+
assert response.status_code == 200, response.data
136136

137137

138138
@pytest.mark.django_db

0 commit comments

Comments
 (0)