asynchronous refactoring
- don't execute celery tasks directly - introduce optional parameters to fileserver tasks to allow chaining - handle user/group/key create and delete tasks in new osusers.signals class - adapt unit tests - change TaskResults model to store the task signatures - generalize the local settings' logging configuration
This commit is contained in:
parent
bcfea10e6f
commit
d5bba7a22d
12 changed files with 290 additions and 170 deletions
|
@ -4,6 +4,7 @@ This module contains the :py:class:`django.apps.AppConfig` instance for the
|
|||
|
||||
"""
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.apps import AppConfig
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
@ -15,3 +16,6 @@ class OsusersAppConfig(AppConfig):
|
|||
"""
|
||||
name = 'osusers'
|
||||
verbose_name = _('Operating System Users and Groups')
|
||||
|
||||
def ready(self):
|
||||
import osusers.signals
|
||||
|
|
|
@ -10,9 +10,12 @@ import logging
|
|||
import os
|
||||
import six
|
||||
|
||||
from celery import group
|
||||
|
||||
from django.db import models, transaction
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.dispatch import Signal
|
||||
from django.utils import timezone
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from django.utils.translation import ugettext as _
|
||||
|
@ -24,28 +27,13 @@ from passlib.utils import generate_password
|
|||
|
||||
from taskresults.models import TaskResult
|
||||
|
||||
from ldaptasks.tasks import (
|
||||
add_ldap_user_to_group,
|
||||
create_ldap_group,
|
||||
create_ldap_user,
|
||||
delete_ldap_group,
|
||||
delete_ldap_user,
|
||||
remove_ldap_user_from_group,
|
||||
set_ldap_user_password,
|
||||
)
|
||||
|
||||
from fileservertasks.tasks import (
|
||||
delete_file_mail_userdir,
|
||||
delete_file_sftp_userdir,
|
||||
set_file_ssh_authorized_keys,
|
||||
setup_file_mail_userdir,
|
||||
setup_file_sftp_userdir,
|
||||
)
|
||||
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
password_set = Signal(providing_args=['instance', 'password'])
|
||||
|
||||
|
||||
CANNOT_USE_PRIMARY_GROUP_AS_ADDITIONAL = _(
|
||||
"You can not use a user's primary group.")
|
||||
|
||||
|
@ -108,9 +96,6 @@ class Group(TimeStampedModel, models.Model):
|
|||
|
||||
"""
|
||||
super(Group, self).save(*args, **kwargs)
|
||||
dn = create_ldap_group.delay(
|
||||
self.groupname, self.gid, self.descr).get()
|
||||
_LOGGER.info("created LDAP group with dn %s", dn)
|
||||
return self
|
||||
|
||||
@transaction.atomic
|
||||
|
@ -124,10 +109,6 @@ class Group(TimeStampedModel, models.Model):
|
|||
:py:meth:`django.db.Model.delete`
|
||||
|
||||
"""
|
||||
TaskResult.objects.create_task_result(
|
||||
delete_ldap_group.delay(self.groupname),
|
||||
'delete_ldap_group'
|
||||
)
|
||||
super(Group, self).delete(*args, **kwargs)
|
||||
|
||||
|
||||
|
@ -249,25 +230,13 @@ class User(TimeStampedModel, models.Model):
|
|||
"""
|
||||
if hasattr(self, 'shadow'):
|
||||
self.shadow.set_password(password)
|
||||
success = set_ldap_user_password.delay(
|
||||
self.username, password).get()
|
||||
if success:
|
||||
_LOGGER.info(
|
||||
"successfully set LDAP password for %s", self.username)
|
||||
else:
|
||||
_LOGGER.error(
|
||||
"setting the LDAP password for %s failed", self.username)
|
||||
return success
|
||||
else:
|
||||
self.shadow = Shadow.objects.create_shadow(
|
||||
user=self, password=password
|
||||
)
|
||||
dn = create_ldap_user.delay(
|
||||
self.username, self.uid, self.group.gid, self.gecos,
|
||||
self.homedir, self.shell, password
|
||||
).get()
|
||||
_LOGGER.info("set LDAP password for %s", dn)
|
||||
return True
|
||||
password_set.send(
|
||||
sender=self.__class__, password=password, instance=self)
|
||||
return True
|
||||
|
||||
def is_sftp_user(self):
|
||||
return self.additionalgroup_set.filter(
|
||||
|
@ -288,22 +257,6 @@ class User(TimeStampedModel, models.Model):
|
|||
:rtype: :py:class:`osusers.models.User`
|
||||
|
||||
"""
|
||||
dn = create_ldap_user.delay(
|
||||
self.username, self.uid, self.group.gid, self.gecos,
|
||||
self.homedir, self.shell, password=None).get()
|
||||
TaskResult.objects.create_task_result(
|
||||
setup_file_sftp_userdir.delay(self.username),
|
||||
'setup_file_sftp_userdir'
|
||||
)
|
||||
TaskResult.objects.create_task_result(
|
||||
setup_file_mail_userdir.delay(self.username),
|
||||
'setup_file_mail_userdir'
|
||||
)
|
||||
_LOGGER.info(
|
||||
"created user %(user)s with LDAP dn %(dn)s, scheduled home "
|
||||
"directory and mail base directory creation.", {
|
||||
'user': self, 'dn': dn,
|
||||
})
|
||||
return super(User, self).save(*args, **kwargs)
|
||||
|
||||
@transaction.atomic
|
||||
|
@ -318,18 +271,6 @@ class User(TimeStampedModel, models.Model):
|
|||
:py:meth:`django.db.Model.delete`
|
||||
|
||||
"""
|
||||
TaskResult.objects.create_task_result(
|
||||
delete_file_mail_userdir.delay(self.username),
|
||||
'delete_file_mail_userdir'
|
||||
)
|
||||
TaskResult.objects.create_task_result(
|
||||
delete_file_sftp_userdir.delay(self.username),
|
||||
'delete_file_sftp_userdir'
|
||||
)
|
||||
for group in [ag.group for ag in self.additionalgroup_set.all()]:
|
||||
remove_ldap_user_from_group.delay(
|
||||
self.username, group.groupname).get()
|
||||
delete_ldap_user.delay(self.username).get()
|
||||
self.group.delete()
|
||||
super(User, self).delete(*args, **kwargs)
|
||||
|
||||
|
@ -460,8 +401,6 @@ class AdditionalGroup(TimeStampedModel, models.Model):
|
|||
:rtype: :py:class:`AdditionalGroup <osusers.models.AdditionalGroup>`
|
||||
|
||||
"""
|
||||
add_ldap_user_to_group.delay(
|
||||
self.user.username, self.group.groupname).get()
|
||||
return super(AdditionalGroup, self).save(*args, **kwargs)
|
||||
|
||||
@transaction.atomic
|
||||
|
@ -474,11 +413,6 @@ class AdditionalGroup(TimeStampedModel, models.Model):
|
|||
:param kwargs: keyword arguments to be passed on to
|
||||
:py:meth:`django.db.Model.delete`
|
||||
"""
|
||||
TaskResult.objects.create_task_result(
|
||||
remove_ldap_user_from_group.delay(
|
||||
self.user.username, self.group.groupname),
|
||||
'remove_ldap_user_from_group'
|
||||
)
|
||||
super(AdditionalGroup, self).delete(*args, **kwargs)
|
||||
|
||||
|
||||
|
@ -583,24 +517,3 @@ class SshPublicKey(TimeStampedModel):
|
|||
return "{algorithm} {data} {comment}".format(
|
||||
algorithm=self.algorithm, data=self.data, comment=self.comment
|
||||
).strip()
|
||||
|
||||
def save(self, **kwargs):
|
||||
key = super(SshPublicKey, self).save(**kwargs)
|
||||
TaskResult.objects.create_task_result(
|
||||
set_file_ssh_authorized_keys.delay(
|
||||
self.user.username, [
|
||||
str(key) for key in
|
||||
SshPublicKey.objects.filter(user=self.user)]),
|
||||
'set_file_ssh_authorized_keys'
|
||||
)
|
||||
return key
|
||||
|
||||
def delete(self, **kwargs):
|
||||
super(SshPublicKey, self).delete(**kwargs)
|
||||
TaskResult.objects.create_task_result(
|
||||
set_file_ssh_authorized_keys.delay(
|
||||
self.user.username, [
|
||||
str(key) for key in
|
||||
SshPublicKey.objects.filter(user=self.user)]),
|
||||
'set_file_ssh_authorized_keys'
|
||||
)
|
||||
|
|
160
gnuviechadmin/osusers/signals.py
Normal file
160
gnuviechadmin/osusers/signals.py
Normal file
|
@ -0,0 +1,160 @@
|
|||
"""
|
||||
This module contains the signal handlers of the :py:mod:`osusers` app.
|
||||
|
||||
"""
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
import logging
|
||||
|
||||
from django.db.models.signals import (
|
||||
m2m_changed,
|
||||
post_delete,
|
||||
post_save,
|
||||
)
|
||||
from django.dispatch import receiver
|
||||
|
||||
from celery import chain, group
|
||||
|
||||
from fileservertasks.tasks import (
|
||||
delete_file_mail_userdir,
|
||||
delete_file_sftp_userdir,
|
||||
set_file_ssh_authorized_keys,
|
||||
setup_file_mail_userdir,
|
||||
setup_file_sftp_userdir,
|
||||
)
|
||||
from ldaptasks.tasks import (
|
||||
add_ldap_user_to_group,
|
||||
create_ldap_group,
|
||||
create_ldap_user,
|
||||
delete_ldap_group,
|
||||
delete_ldap_user,
|
||||
remove_ldap_user_from_group,
|
||||
set_ldap_user_password,
|
||||
)
|
||||
from taskresults.models import TaskResult
|
||||
|
||||
from .models import (
|
||||
AdditionalGroup,
|
||||
Group,
|
||||
SshPublicKey,
|
||||
User,
|
||||
password_set,
|
||||
)
|
||||
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@receiver(password_set, sender=User)
|
||||
def handle_user_password_set(sender, instance, password, **kwargs):
|
||||
taskresult = TaskResult.objects.create_task_result(
|
||||
'handle_user_password_set',
|
||||
set_ldap_user_password.s(instance.username, password))
|
||||
_LOGGER.info(
|
||||
'LDAP password change has been requested in task %s',
|
||||
taskresult.task_id)
|
||||
|
||||
|
||||
#@receiver(post_save)
|
||||
#def handle_post_save(sender, **kwargs):
|
||||
# _LOGGER.debug(
|
||||
# 'handling post_save signal for %s with args %s',
|
||||
# sender, kwargs)
|
||||
|
||||
|
||||
@receiver(post_save, sender=Group)
|
||||
def handle_group_created(sender, instance, created, **kwargs):
|
||||
if created:
|
||||
taskresult = TaskResult.objects.create_task_result(
|
||||
'handle_group_created',
|
||||
create_ldap_group.s(
|
||||
instance.groupname, instance.gid, instance.descr))
|
||||
_LOGGER.info(
|
||||
'LDAP group creation has been requested in task %s',
|
||||
taskresult.task_id)
|
||||
_LOGGER.debug(
|
||||
'group %s has been %s', instance, created and "created" or "updated")
|
||||
|
||||
|
||||
@receiver(post_save, sender=User)
|
||||
def handle_user_created(sender, instance, created, **kwargs):
|
||||
if created:
|
||||
chain = create_ldap_user.s(
|
||||
instance.username, instance.uid, instance.group.gid,
|
||||
instance.gecos, instance.homedir, instance.shell, None
|
||||
) | setup_file_sftp_userdir.s(instance.username
|
||||
) | setup_file_mail_userdir.s(instance.username)
|
||||
taskresult = TaskResult.objects.create_task_result(
|
||||
'handle_user_created', chain)
|
||||
_LOGGER.info(
|
||||
'LDAP user creation has been requested in task %s',
|
||||
taskresult.task_id)
|
||||
_LOGGER.debug(
|
||||
'user %s has been %s', instance, created and "created" or "updated")
|
||||
|
||||
|
||||
@receiver(post_save, sender=AdditionalGroup)
|
||||
def handle_user_added_to_group(sender, instance, created, **kwargs):
|
||||
if created:
|
||||
taskresult = TaskResult.objects.create_task_result(
|
||||
'handle_user_added_to_group',
|
||||
add_ldap_user_to_group.s(
|
||||
instance.user.username, instance.group.groupname))
|
||||
_LOGGER.info(
|
||||
'Adding user to LDAP group has been requested in task %s',
|
||||
taskresult.task_id)
|
||||
|
||||
|
||||
@receiver(post_save, sender=SshPublicKey)
|
||||
@receiver(post_delete, sender=SshPublicKey)
|
||||
def handle_ssh_keys_changed(sender, instance, **kwargs):
|
||||
sig = set_file_ssh_authorized_keys.s(
|
||||
instance.user.username, [
|
||||
str(key) for key in
|
||||
SshPublicKey.objects.filter(user=instance.user)])
|
||||
taskresult = TaskResult.objects.create_task_result(
|
||||
'handle_ssh_keys_changed', sig)
|
||||
_LOGGER.info(
|
||||
'Change of SSH keys has been requested in task %s',
|
||||
taskresult.task_id)
|
||||
|
||||
|
||||
#@receiver(post_delete)
|
||||
#def handle_post_delete(sender, **kwargs):
|
||||
# _LOGGER.debug(
|
||||
# 'handling post_delete signal for %s with args %s',
|
||||
# sender, kwargs)
|
||||
|
||||
|
||||
@receiver(post_delete, sender=Group)
|
||||
def handle_group_deleted(sender, instance, **kwargs):
|
||||
taskresult = TaskResult.objects.create_task_result(
|
||||
'handle_group_deleted',
|
||||
delete_ldap_group.s(instance.groupname))
|
||||
_LOGGER.info(
|
||||
'LDAP group deletion has been requested in task %s',
|
||||
taskresult.task_id)
|
||||
|
||||
|
||||
@receiver(post_delete, sender=User)
|
||||
def handle_user_deleted(sender, instance, **kwargs):
|
||||
chain = delete_file_mail_userdir.s(instance.username
|
||||
) | delete_file_sftp_userdir.s(instance.username
|
||||
) | delete_ldap_user.s(instance.username)
|
||||
_LOGGER.debug('chain signature %s', chain)
|
||||
taskresult = TaskResult.objects.create_task_result(
|
||||
'handle_user_deleted', chain)
|
||||
_LOGGER.info(
|
||||
'LDAP user deletion has been requested in task %s',
|
||||
taskresult.task_id)
|
||||
|
||||
|
||||
@receiver(post_delete, sender=AdditionalGroup)
|
||||
def handle_user_removed_from_group(sender, instance, **kwargs):
|
||||
taskresult = TaskResult.objects.create_task_result(
|
||||
'handle_user_removed_from_group',
|
||||
remove_ldap_user_from_group.s(
|
||||
instance.user.username, instance.group.groupname))
|
||||
_LOGGER.info(
|
||||
'Removing user from LDAP group has been requested in task %s',
|
||||
taskresult.task_id)
|
|
@ -128,8 +128,12 @@ class AdditionalGroupTest(TestCaseWithCeleryTasks):
|
|||
addgroup = AdditionalGroup(user=self.user, group=group2)
|
||||
addgroup.save()
|
||||
taskres = TaskResult.objects.all()
|
||||
self.assertTrue(len(taskres), 1)
|
||||
self.assertEqual(taskres[0].task_name, 'setup_file_sftp_userdir')
|
||||
self.assertTrue(len(taskres), 4)
|
||||
creators = [r.creator for r in taskres]
|
||||
for tcount, tcreator in [
|
||||
(2, 'handle_group_created'), (1, 'handle_user_created'),
|
||||
(1, 'handle_user_added_to_group')]:
|
||||
self.assertEqual(creators.count(tcreator), tcount)
|
||||
|
||||
def test_delete(self):
|
||||
group2 = Group.objects.create(groupname='test2', gid=1001)
|
||||
|
@ -167,9 +171,9 @@ class GroupTest(TestCaseWithCeleryTasks):
|
|||
self.assertEqual(len(Group.objects.all()), 1)
|
||||
group.delete()
|
||||
self.assertEqual(len(Group.objects.all()), 0)
|
||||
self.assertEqual(len(TaskResult.objects.all()), 1)
|
||||
self.assertEqual(len(TaskResult.objects.all()), 2)
|
||||
tr = TaskResult.objects.first()
|
||||
self.assertEqual(tr.task_name, 'delete_ldap_group')
|
||||
self.assertEqual(tr.creator, 'handle_group_created')
|
||||
|
||||
|
||||
class ShadowManagerTest(TestCaseWithCeleryTasks):
|
||||
|
@ -275,10 +279,12 @@ class UserManagerTest(TestCaseWithCeleryTasks):
|
|||
def test_create_user_tasks(self):
|
||||
User.objects.create_user(customer=self.customer)
|
||||
taskres = TaskResult.objects.all()
|
||||
self.assertEqual(len(taskres), 2)
|
||||
tasknames = [r.task_name for r in taskres]
|
||||
self.assertEqual(tasknames.count('setup_file_sftp_userdir'), 1)
|
||||
self.assertEqual(tasknames.count('setup_file_mail_userdir'), 1)
|
||||
self.assertEqual(len(taskres), 3)
|
||||
creators = [r.creator for r in taskres]
|
||||
for creator in [
|
||||
'handle_group_created', 'handle_user_created',
|
||||
'handle_user_password_set']:
|
||||
self.assertIn(creator, creators)
|
||||
|
||||
def test_create_user_second(self):
|
||||
User.objects.create_user(customer=self.customer)
|
||||
|
@ -351,24 +357,26 @@ class UserTest(TestCaseWithCeleryTasks):
|
|||
|
||||
def test_save(self):
|
||||
user = User.objects.create_user(self.customer)
|
||||
TaskResult.objects.all().delete()
|
||||
user.save()
|
||||
taskres = TaskResult.objects.all()
|
||||
self.assertEqual(len(taskres), 2)
|
||||
task_names = [r.task_name for r in taskres]
|
||||
self.assertIn('setup_file_sftp_userdir', task_names)
|
||||
self.assertIn('setup_file_mail_userdir', task_names)
|
||||
self.assertEqual(len(taskres), 3)
|
||||
creators = [r.creator for r in taskres]
|
||||
for task in [
|
||||
'handle_group_created', 'handle_user_created',
|
||||
'handle_user_password_set']:
|
||||
self.assertIn(task, creators)
|
||||
|
||||
def test_delete_only_user(self):
|
||||
user = User.objects.create_user(self.customer)
|
||||
TaskResult.objects.all().delete()
|
||||
user.delete()
|
||||
taskres = TaskResult.objects.all()
|
||||
self.assertEqual(len(taskres), 3)
|
||||
tasknames = [r.task_name for r in taskres]
|
||||
self.assertEqual(tasknames.count('delete_file_mail_userdir'), 1)
|
||||
self.assertEqual(tasknames.count('delete_file_sftp_userdir'), 1)
|
||||
self.assertEqual(tasknames.count('delete_ldap_group'), 1)
|
||||
self.assertEqual(len(taskres), 6)
|
||||
creators = [r.creator for r in taskres]
|
||||
for task in [
|
||||
'handle_group_created', 'handle_user_created',
|
||||
'handle_user_password_set', 'handle_user_deleted',
|
||||
'handle_group_deleted', 'handle_user_deleted']:
|
||||
self.assertIn(task, creators)
|
||||
self.assertEqual(len(User.objects.all()), 0)
|
||||
|
||||
def test_delete_additional_groups(self):
|
||||
|
@ -381,11 +389,12 @@ class UserTest(TestCaseWithCeleryTasks):
|
|||
TaskResult.objects.all().delete()
|
||||
user.delete()
|
||||
taskres = TaskResult.objects.all()
|
||||
self.assertEqual(len(taskres), 3)
|
||||
tasknames = [t.task_name for t in taskres]
|
||||
self.assertEqual(tasknames.count('delete_file_mail_userdir'), 1)
|
||||
self.assertEqual(tasknames.count('delete_file_sftp_userdir'), 1)
|
||||
self.assertEqual(tasknames.count('delete_ldap_group'), 1)
|
||||
self.assertEqual(len(taskres), 5)
|
||||
creators = [t.creator for t in taskres]
|
||||
for tcount, tcreator in [
|
||||
(2, 'handle_user_removed_from_group'), (2, 'handle_user_deleted'),
|
||||
(1, 'handle_group_deleted')]:
|
||||
self.assertEqual(creators.count(tcreator), tcount)
|
||||
self.assertEqual(len(User.objects.all()), 0)
|
||||
self.assertEqual(len(AdditionalGroup.objects.all()), 0)
|
||||
|
||||
|
@ -497,7 +506,7 @@ class SshPublicKeyTest(TestCaseWithCeleryTasks):
|
|||
taskresults = TaskResult.objects.all()
|
||||
self.assertEqual(len(taskresults), 1)
|
||||
self.assertEqual(
|
||||
taskresults[0].task_name, 'set_file_ssh_authorized_keys')
|
||||
taskresults[0].creator, 'handle_ssh_keys_changed')
|
||||
|
||||
def test_call_tasks_on_delete(self):
|
||||
key = SshPublicKey.objects.create_ssh_public_key(
|
||||
|
@ -507,4 +516,4 @@ class SshPublicKeyTest(TestCaseWithCeleryTasks):
|
|||
taskresults = TaskResult.objects.all()
|
||||
self.assertEqual(len(taskresults), 1)
|
||||
self.assertEqual(
|
||||
taskresults[0].task_name, 'set_file_ssh_authorized_keys')
|
||||
taskresults[0].creator, 'handle_ssh_keys_changed')
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue