This repository has been archived on 2026-10-23. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
neuf-userinfo/neuf_userinfo/management/commands/sync_active_to_internal_systems.py
2017-01-11 22:14:52 +01:00

172 lines
7.0 KiB
Python

from datetime import datetime
from django.core.management.base import BaseCommand
from django.db.models import Q
from inside.models import InsideGroup, InsideUser
from neuf_ldap.models import LdapGroup, LdapUser
from neuf_ldap.utils import create_ldap_user, ldap_update_user_details, create_ldap_automount, ldap_update_user_groups
from optparse import make_option
from neuf_userinfo.ssh import create_home_dir
ACTIVE_USERS_GROUP = 'dns-aktiv'
class Command(BaseCommand):
help = 'Synchronizes users in group dns-aktiv from Inside to LDAP'
option_list = BaseCommand.option_list + (
make_option(
'--dry-run',
action='store_true',
dest='dry_run',
default=False,
help='Dry run when syncronizing, does not save anything.'
),
make_option(
'--delete-group-memberships',
action='store_true',
dest='delete_group_memberships',
default=False,
help='Toggle if group memberships syncronization should delete or not'
),)
DIFF_ATTRIBUTES = ['first_name', 'last_name', 'email']
SYNC_GROUP_PREFIX = 'dns-'
COUNTS = dict(create=0, update=0, in_sync=0)
options = {}
def handle(self, *args, **options):
self.options = options
if int(self.options['verbosity']) >= 2:
self.stdout.write('[{}] Started sync job'.format(datetime.utcnow()))
# Get all active user from Inside
inside_users_diffable = self.get_inside_users_diffable()
# Get all existing users in LDAP
ldap_users_diffable = self.get_all_ldap_users_diffable()
# Do actual sync
self.sync_users(inside_users_diffable, ldap_users_diffable)
self.log_totals()
if int(self.options['verbosity']) >= 2:
self.stdout.write('[{}] Finished sync job'.format(datetime.utcnow()))
# Voila!
def get_inside_users_diffable(self):
inside_users_diffable = {}
group = InsideGroup.objects.get(posix_group=ACTIVE_USERS_GROUP)
inside_users = InsideUser.objects.filter(group_rels__group=group)
inside_users = inside_users.exclude(
Q(ldap_username__isnull=True)
| Q(registration_status='partial')
| Q(ldap_password__isnull=True))
for u in inside_users:
inside_groups = InsideGroup.objects.filter(user_rels__user=u).exclude(posix_group='')
inside_groups = inside_groups.values_list('posix_group', flat=True)
inside_users_diffable[u.ldap_username] = {
'username': u.ldap_username,
'first_name': u.first_name,
'last_name': u.last_name,
'ldap_password': u.ldap_password,
'email': u.email,
'groups': inside_groups
}
if self.options['verbosity'] == '3':
self.stdout.write('Found {} Inside users'.format(len(inside_users_diffable)))
return inside_users_diffable
def get_all_ldap_users_diffable(self):
ldap_users_diffable = {}
ldap_users = LdapUser.objects.all()
for u in ldap_users:
ldap_groups = LdapGroup.objects\
.filter(name__startswith=self.SYNC_GROUP_PREFIX, members__contains=u.username)\
.values_list('name', flat=True)
ldap_users_diffable[u.username] = {
'username': u.username,
'first_name': u.first_name,
'last_name': u.last_name,
'email': u.email,
'groups': ldap_groups
}
if self.options['verbosity'] == '3':
self.stdout.write('Found {} LDAP users'.format(len(ldap_users_diffable)))
return ldap_users_diffable
def sync_users(self, inside_users_diffable, ldap_users_diffable):
for username, user in inside_users_diffable.items():
if username not in ldap_users_diffable:
# Create
create_ldap_user(user, dry_run=self.options['dry_run'])
create_home_dir(user['username'], dry_run=self.options['dry_run'])
create_ldap_automount(user['username'], dry_run=self.options['dry_run'])
self.COUNTS['create'] += 1
if int(self.options['verbosity']) >= 2:
self.stdout.write('[CREATED] Inside user {} is not in LDAP'.format(username))
elif not self.user_details_in_sync(user, ldap_users_diffable[username]) or not self.user_groups_in_sync(user, ldap_users_diffable[username]):
# Update
ldap_update_user_details(user, dry_run=self.options['dry_run'])
ldap_update_user_groups(
user,
ldap_users_diffable[username],
dry_run=self.options['dry_run'],
delete_group_memberships=self.options['delete_group_memberships'])
self.COUNTS['update'] += 1
if int(self.options['verbosity']) >= 2:
self.stdout.write('[UPDATED] Inside user {} is out of sync with LDAP'.format(username))
else:
# In sync :-)
self.COUNTS['in_sync'] += 1
if int(self.options['verbosity']) == 3:
self.stdout.write('[OK] Inside user {} is in sync with LDAP'.format(username))
def log_totals(self):
if self.COUNTS['create'] > 0 or self.COUNTS['update'] > 0 or int(self.options['verbosity']) >= 2:
self.stdout.write('Totals: created {}, updated {}, in sync: {}'.format(
self.COUNTS['create'],
self.COUNTS['update'],
self.COUNTS['in_sync']))
def user_details_in_sync(self, inside_user, ldap_user):
for attr in self.DIFF_ATTRIBUTES:
if inside_user[attr] != ldap_user[attr]:
if int(self.options['verbosity']) >= 2:
self.stdout.write('{}: {} (Inside) != {} (LDAP)'.format(
inside_user['username'],
inside_user[attr],
ldap_user[attr]))
return False
return True
def user_groups_in_sync(self, inside_user, ldap_user):
# Compare set of group names
inside_groups = set(inside_user['groups'])
ldap_groups = set(ldap_user['groups'])
if self.options['delete_group_memberships']:
in_sync = inside_groups == ldap_groups
if not in_sync and int(self.options['verbosity']) >= 2:
self.stdout.write('{}: {} (Inside) != {} (LDAP)'.format(
inside_user['username'],
','.join(inside_groups),
','.join(ldap_groups)))
else:
missing_groups = inside_groups.difference(ldap_groups)
in_sync = len(missing_groups) == 0
if not in_sync and int(self.options['verbosity']) >= 2:
self.stdout.write('{}: Missing groups in LDAP: {}'.format(
inside_user['username'],
','.join(missing_groups)))
return in_sync