Skip to content

Commit e12d458

Browse files
committed
Extend scope for transaction for groups in migration and lock groups
1 parent f1a29f5 commit e12d458

File tree

2 files changed

+20
-20
lines changed

2 files changed

+20
-20
lines changed

rbac/management/group/view.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -185,10 +185,10 @@ class GroupViewSet(
185185

186186
def get_queryset(self):
187187
"""Obtain queryset for requesting user based on access."""
188-
add_principals_method = self.action == "principals" and self.request.method == "POST"
188+
principals_method = self.action == "principals" and (self.request.method != "GET")
189189
destroy_method = self.action == "destroy"
190190

191-
if add_principals_method or destroy_method:
191+
if principals_method or destroy_method:
192192
# In this case, the group must be locked to prevent principal changes during deletion.
193193
# If not locked, replication to relations may be out of sync due to phantom reads.
194194
# We have to modify the starting queryset to support locking because

rbac/migration_tool/migrate.py

+18-18
Original file line numberDiff line numberDiff line change
@@ -40,24 +40,24 @@
4040

4141
def migrate_groups_for_tenant(tenant: Tenant, replicator: RelationReplicator):
4242
"""Generate user relationships and system role assignments for groups in a tenant."""
43-
groups = tenant.group_set.all()
43+
groups = tenant.group_set.values("pk")
4444
for group in groups:
45-
principals: list[Principal] = []
46-
system_roles: list[Role] = []
47-
if not group.platform_default:
48-
principals = group.principals.all()
49-
if group.system is False and group.admin_default is False:
50-
system_roles = group.roles().public_tenant_only()
51-
if any(True for _ in system_roles) or any(True for _ in principals):
52-
# The migrator deals with concurrency control.
53-
# We need an atomic block because the select_for_update is used in the dual write handler,
54-
# and the group must be locked to add principals to the groups.
55-
# NOTE: The lock on the group is not necessary when adding system roles to the group,
56-
# as the binding mappings are locked during this process to ensure concurrency control.
57-
# Start of transaction for group operations
58-
with transaction.atomic():
59-
# Lock group
60-
Group.objects.select_for_update().get(pk=group.pk)
45+
# The migrator deals with concurrency control.
46+
# We need an atomic block because the select_for_update is used in the dual write handler,
47+
# and the group must be locked to add principals to the groups.
48+
# NOTE: The lock on the group is not necessary when adding system roles to the group,
49+
# as the binding mappings are locked during this process to ensure concurrency control.
50+
# Start of transaction for group operations
51+
with transaction.atomic():
52+
# Requery the group with a lock
53+
group = Group.objects.select_for_update().get(pk=group["pk"])
54+
principals: list[Principal] = []
55+
system_roles: list[Role] = []
56+
if not group.platform_default:
57+
principals = group.principals.all()
58+
if group.system is False and group.admin_default is False:
59+
system_roles = group.roles().public_tenant_only()
60+
if any(True for _ in system_roles) or any(True for _ in principals):
6161
dual_write_handler = RelationApiDualWriteGroupHandler(
6262
group, ReplicationEventType.MIGRATE_TENANT_GROUPS, replicator=replicator
6363
)
@@ -68,7 +68,7 @@ def migrate_groups_for_tenant(tenant: Tenant, replicator: RelationReplicator):
6868
# dual_write_handler
6969
dual_write_handler.generate_relations_to_add_roles(system_roles)
7070
dual_write_handler.replicate()
71-
# End of transaction for group operations, locks are released
71+
# End of transaction for group operations, locks are released
7272

7373

7474
def migrate_roles_for_tenant(tenant, exclude_apps, replicator):

0 commit comments

Comments
 (0)