1
0
mirror of https://github.com/quay/quay.git synced 2026-01-26 06:21:37 +03:00
Files
quay/data/users/teamsync.py
Sunandadadi 6bf6c2b181 teamsync: run team sync worker for teams synced via ldap or keystone (PROJQUAY-6762) (#2788)
* teamsync: run team sync worker for teams synced via ldap or keystone (PROJQUAY-6762)

* fix comment

* adding test

* isort fix
2024-04-29 13:18:04 -04:00

190 lines
6.6 KiB
Python

import json
import logging
from data import model
logger = logging.getLogger(__name__)
MAX_TEAMS_PER_ITERATION = 500
def sync_teams_to_groups(authentication, stale_cutoff):
"""
Performs team syncing by looking up any stale team(s) found, and performing the sync operation
on them.
"""
logger.debug("Looking up teams to sync to groups")
sync_team_tried = set()
supported_services = ["ldap", "keystone"]
while len(sync_team_tried) < MAX_TEAMS_PER_ITERATION:
# Find a stale team.
stale_team_sync = model.team.get_stale_team(stale_cutoff, supported_services)
if not stale_team_sync:
logger.debug("No additional stale team found; sleeping")
return
# Make sure we don't try to reprocess a team on this iteration.
if stale_team_sync.id in sync_team_tried:
break
sync_team_tried.add(stale_team_sync.id)
# Sync the team.
sync_successful = sync_team(authentication, stale_team_sync)
if not sync_successful:
return
def sync_team(authentication, stale_team_sync):
"""
Performs synchronization of a team (as referenced by the TeamSync stale_team_sync).
Returns True on success and False otherwise.
"""
sync_config = json.loads(stale_team_sync.config)
logger.info(
"Syncing team `%s` under organization %s via %s (#%s)",
stale_team_sync.team.name,
stale_team_sync.team.organization.username,
sync_config,
stale_team_sync.team_id,
extra={"team": stale_team_sync.team_id, "sync_config": sync_config},
)
# Load all the existing members of the team in Quay that are bound to the auth service.
existing_users = model.team.get_federated_team_member_mapping(
stale_team_sync.team, authentication.federated_service
)
logger.debug(
"Existing membership of %s for team `%s` under organization %s via %s (#%s)",
len(existing_users),
stale_team_sync.team.name,
stale_team_sync.team.organization.username,
sync_config,
stale_team_sync.team_id,
extra={
"team": stale_team_sync.team_id,
"sync_config": sync_config,
"existing_member_count": len(existing_users),
},
)
# Load all the members of the team from the authenication system.
(member_iterator, err) = authentication.iterate_group_members(sync_config)
if err is not None:
logger.error(
"Got error when trying to iterate group members with config %s: %s", sync_config, err
)
return False
# Collect all the members currently found in the group, adding them to the team as we go
# along.
group_membership = set()
for member_info, err in member_iterator:
if err is not None:
logger.error("Got error when trying to construct a member: %s", err)
continue
# If the member is already in the team, nothing more to do.
if member_info.username in existing_users:
logger.debug(
"Member %s already in team `%s` under organization %s via %s (#%s)",
member_info.username,
stale_team_sync.team.name,
stale_team_sync.team.organization.username,
sync_config,
stale_team_sync.team_id,
extra={
"team": stale_team_sync.team_id,
"sync_config": sync_config,
"member": member_info.username,
},
)
group_membership.add(existing_users[member_info.username])
continue
# Retrieve the Quay user associated with the member info.
(quay_user, err) = authentication.get_and_link_federated_user_info(
member_info, internal_create=True
)
if err is not None:
logger.error(
"Could not link external user %s to an internal user: %s",
member_info.username,
err,
extra={
"team": stale_team_sync.team_id,
"sync_config": sync_config,
"member": member_info.username,
"error": err,
},
)
continue
# Add the user to the membership set.
group_membership.add(quay_user.id)
# Add the user to the team.
try:
logger.info(
"Adding member %s to team `%s` under organization %s via %s (#%s)",
quay_user.username,
stale_team_sync.team.name,
stale_team_sync.team.organization.username,
sync_config,
stale_team_sync.team_id,
extra={
"team": stale_team_sync.team_id,
"sync_config": sync_config,
"member": quay_user.username,
},
)
model.team.add_user_to_team(quay_user, stale_team_sync.team)
except model.UserAlreadyInTeam:
# If the user is already present, nothing more to do for them.
pass
# Update the transaction and last_updated time of the team sync. Only if it matches
# the current value will we then perform the deletion step.
got_transaction_handle = model.team.update_sync_status(stale_team_sync)
if not got_transaction_handle:
# Another worker updated this team. Nothing more to do.
logger.debug(
"Another worker synced team `%s` under organization %s via %s (#%s)",
stale_team_sync.team.name,
stale_team_sync.team.organization.username,
sync_config,
stale_team_sync.team_id,
extra={"team": stale_team_sync.team_id, "sync_config": sync_config},
)
return True
# Delete any team members not found in the backing auth system.
logger.debug(
"Deleting stale members for team `%s` under organization %s via %s (#%s)",
stale_team_sync.team.name,
stale_team_sync.team.organization.username,
sync_config,
stale_team_sync.team_id,
extra={"team": stale_team_sync.team_id, "sync_config": sync_config},
)
deleted = model.team.delete_members_not_present(stale_team_sync.team, group_membership)
# Done!
logger.info(
"Finishing sync for team `%s` under organization %s via %s (#%s): %s deleted",
stale_team_sync.team.name,
stale_team_sync.team.organization.username,
sync_config,
stale_team_sync.team_id,
deleted,
extra={"team": stale_team_sync.team_id, "sync_config": sync_config},
)
return True