861e81cccd
Before this change, if user creation was disabled, team sync would fail to sync over users that had not yet been invited/logged in, because their accounts could not be created. Following this change, team syncing of users not yet in the system will create those user accounts, allowing users to be "auto invited" via team sync. Fixes https://jira.coreos.com/browse/QUAY-910
136 lines
6 KiB
Python
136 lines
6 KiB
Python
import logging
|
|
import json
|
|
|
|
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()
|
|
while len(sync_team_tried) < MAX_TEAMS_PER_ITERATION:
|
|
# Find a stale team.
|
|
stale_team_sync = model.team.get_stale_team(stale_cutoff)
|
|
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
|