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
|
@ -9,7 +9,7 @@ from celery import shared_task
|
||||||
|
|
||||||
|
|
||||||
@shared_task
|
@shared_task
|
||||||
def setup_file_sftp_userdir(username):
|
def setup_file_sftp_userdir(username, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
This task creates the home directory for an SFTP user if it does not exist
|
This task creates the home directory for an SFTP user if it does not exist
|
||||||
yet.
|
yet.
|
||||||
|
@ -23,7 +23,7 @@ def setup_file_sftp_userdir(username):
|
||||||
|
|
||||||
|
|
||||||
@shared_task
|
@shared_task
|
||||||
def delete_file_sftp_userdir(username):
|
def delete_file_sftp_userdir(username, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
This task recursively deletes the home directory of an SFTP user if it
|
This task recursively deletes the home directory of an SFTP user if it
|
||||||
does not exist yet.
|
does not exist yet.
|
||||||
|
@ -37,7 +37,7 @@ def delete_file_sftp_userdir(username):
|
||||||
|
|
||||||
|
|
||||||
@shared_task
|
@shared_task
|
||||||
def setup_file_mail_userdir(username):
|
def setup_file_mail_userdir(username, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
This task creates the mail base directory for a user if it does not exist
|
This task creates the mail base directory for a user if it does not exist
|
||||||
yet.
|
yet.
|
||||||
|
@ -52,7 +52,7 @@ def setup_file_mail_userdir(username):
|
||||||
|
|
||||||
|
|
||||||
@shared_task
|
@shared_task
|
||||||
def delete_file_mail_userdir(username):
|
def delete_file_mail_userdir(username, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
This task recursively deletes the mail base directory for a user if it
|
This task recursively deletes the mail base directory for a user if it
|
||||||
does not exist yet.
|
does not exist yet.
|
||||||
|
|
|
@ -50,7 +50,7 @@ def navigation(request):
|
||||||
request.path.endswith('/impressum/')
|
request.path.endswith('/impressum/')
|
||||||
):
|
):
|
||||||
context['active_item'] = 'imprint'
|
context['active_item'] = 'imprint'
|
||||||
else:
|
elif not viewmodule.startswith('django.contrib.admin'):
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
'no special handling for view %s in module %s, fallback to '
|
'no special handling for view %s in module %s, fallback to '
|
||||||
'default active menu item %s',
|
'default active menu item %s',
|
||||||
|
|
|
@ -261,6 +261,7 @@ ALLAUTH_APPS = (
|
||||||
LOCAL_APPS = (
|
LOCAL_APPS = (
|
||||||
'dashboard',
|
'dashboard',
|
||||||
'taskresults',
|
'taskresults',
|
||||||
|
'ldaptasks',
|
||||||
'mysqltasks',
|
'mysqltasks',
|
||||||
'pgsqltasks',
|
'pgsqltasks',
|
||||||
'fileservertasks',
|
'fileservertasks',
|
||||||
|
|
|
@ -49,30 +49,13 @@ LOGGING['handlers'].update({
|
||||||
'formatter': 'simple',
|
'formatter': 'simple',
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
LOGGING['loggers'].update({
|
LOGGING['loggers'].update(dict(
|
||||||
'gnuviechadmin': {
|
[(key, {'handlers': ['console'], 'level': 'DEBUG', 'propagate': True,})
|
||||||
'handlers': ['console'], 'level': 'DEBUG', 'propagate': True,},
|
for key in [
|
||||||
'dashboard': {
|
'dashboard', 'domains', 'fileservertasks', 'gvacommon',
|
||||||
'handlers': ['console'], 'level': 'DEBUG', 'propagate': True,},
|
'gvawebcore', 'hostingpackages', 'ldaptasks', 'managemails',
|
||||||
'domains': {
|
'mysqltasks', 'osusers', 'pgsqltasks', 'taskresults',
|
||||||
'handlers': ['console'], 'level': 'DEBUG', 'propagate': True,},
|
'userdbs', 'websites']]))
|
||||||
'gvacommon': {
|
|
||||||
'handlers': ['console'], 'level': 'DEBUG', 'propagate': True,},
|
|
||||||
'gvawebcore': {
|
|
||||||
'handlers': ['console'], 'level': 'DEBUG', 'propagate': True,},
|
|
||||||
'hostingpackages': {
|
|
||||||
'handlers': ['console'], 'level': 'DEBUG', 'propagate': True,},
|
|
||||||
'managemails': {
|
|
||||||
'handlers': ['console'], 'level': 'DEBUG', 'propagate': True,},
|
|
||||||
'osusers': {
|
|
||||||
'handlers': ['console'], 'level': 'DEBUG', 'propagate': True,},
|
|
||||||
'taskresults': {
|
|
||||||
'handlers': ['console'], 'level': 'DEBUG', 'propagate': True,},
|
|
||||||
'userdbs': {
|
|
||||||
'handlers': ['console'], 'level': 'DEBUG', 'propagate': True,},
|
|
||||||
'websites': {
|
|
||||||
'handlers': ['console'], 'level': 'DEBUG', 'propagate': True,},
|
|
||||||
})
|
|
||||||
|
|
||||||
DEBUG_TOOLBAR_PATCH_SETTINGS = False
|
DEBUG_TOOLBAR_PATCH_SETTINGS = False
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ from __future__ import absolute_import
|
||||||
|
|
||||||
from celery import shared_task
|
from celery import shared_task
|
||||||
|
|
||||||
|
|
||||||
@shared_task
|
@shared_task
|
||||||
def create_ldap_group(groupname, gid, descr):
|
def create_ldap_group(groupname, gid, descr):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -4,6 +4,7 @@ This module contains the :py:class:`django.apps.AppConfig` instance for the
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
@ -15,3 +16,6 @@ class OsusersAppConfig(AppConfig):
|
||||||
"""
|
"""
|
||||||
name = 'osusers'
|
name = 'osusers'
|
||||||
verbose_name = _('Operating System Users and Groups')
|
verbose_name = _('Operating System Users and Groups')
|
||||||
|
|
||||||
|
def ready(self):
|
||||||
|
import osusers.signals
|
||||||
|
|
|
@ -10,9 +10,12 @@ import logging
|
||||||
import os
|
import os
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
from celery import group
|
||||||
|
|
||||||
from django.db import models, transaction
|
from django.db import models, transaction
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
|
from django.dispatch import Signal
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.encoding import python_2_unicode_compatible
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
@ -24,28 +27,13 @@ from passlib.utils import generate_password
|
||||||
|
|
||||||
from taskresults.models import TaskResult
|
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__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
password_set = Signal(providing_args=['instance', 'password'])
|
||||||
|
|
||||||
|
|
||||||
CANNOT_USE_PRIMARY_GROUP_AS_ADDITIONAL = _(
|
CANNOT_USE_PRIMARY_GROUP_AS_ADDITIONAL = _(
|
||||||
"You can not use a user's primary group.")
|
"You can not use a user's primary group.")
|
||||||
|
|
||||||
|
@ -108,9 +96,6 @@ class Group(TimeStampedModel, models.Model):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
super(Group, self).save(*args, **kwargs)
|
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
|
return self
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
|
@ -124,10 +109,6 @@ class Group(TimeStampedModel, models.Model):
|
||||||
:py:meth:`django.db.Model.delete`
|
: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)
|
super(Group, self).delete(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@ -249,24 +230,12 @@ class User(TimeStampedModel, models.Model):
|
||||||
"""
|
"""
|
||||||
if hasattr(self, 'shadow'):
|
if hasattr(self, 'shadow'):
|
||||||
self.shadow.set_password(password)
|
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:
|
else:
|
||||||
self.shadow = Shadow.objects.create_shadow(
|
self.shadow = Shadow.objects.create_shadow(
|
||||||
user=self, password=password
|
user=self, password=password
|
||||||
)
|
)
|
||||||
dn = create_ldap_user.delay(
|
password_set.send(
|
||||||
self.username, self.uid, self.group.gid, self.gecos,
|
sender=self.__class__, password=password, instance=self)
|
||||||
self.homedir, self.shell, password
|
|
||||||
).get()
|
|
||||||
_LOGGER.info("set LDAP password for %s", dn)
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def is_sftp_user(self):
|
def is_sftp_user(self):
|
||||||
|
@ -288,22 +257,6 @@ class User(TimeStampedModel, models.Model):
|
||||||
:rtype: :py:class:`osusers.models.User`
|
: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)
|
return super(User, self).save(*args, **kwargs)
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
|
@ -318,18 +271,6 @@ class User(TimeStampedModel, models.Model):
|
||||||
:py:meth:`django.db.Model.delete`
|
: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()
|
self.group.delete()
|
||||||
super(User, self).delete(*args, **kwargs)
|
super(User, self).delete(*args, **kwargs)
|
||||||
|
|
||||||
|
@ -460,8 +401,6 @@ class AdditionalGroup(TimeStampedModel, models.Model):
|
||||||
:rtype: :py:class:`AdditionalGroup <osusers.models.AdditionalGroup>`
|
: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)
|
return super(AdditionalGroup, self).save(*args, **kwargs)
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
|
@ -474,11 +413,6 @@ class AdditionalGroup(TimeStampedModel, models.Model):
|
||||||
:param kwargs: keyword arguments to be passed on to
|
:param kwargs: keyword arguments to be passed on to
|
||||||
:py:meth:`django.db.Model.delete`
|
: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)
|
super(AdditionalGroup, self).delete(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@ -583,24 +517,3 @@ class SshPublicKey(TimeStampedModel):
|
||||||
return "{algorithm} {data} {comment}".format(
|
return "{algorithm} {data} {comment}".format(
|
||||||
algorithm=self.algorithm, data=self.data, comment=self.comment
|
algorithm=self.algorithm, data=self.data, comment=self.comment
|
||||||
).strip()
|
).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 = AdditionalGroup(user=self.user, group=group2)
|
||||||
addgroup.save()
|
addgroup.save()
|
||||||
taskres = TaskResult.objects.all()
|
taskres = TaskResult.objects.all()
|
||||||
self.assertTrue(len(taskres), 1)
|
self.assertTrue(len(taskres), 4)
|
||||||
self.assertEqual(taskres[0].task_name, 'setup_file_sftp_userdir')
|
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):
|
def test_delete(self):
|
||||||
group2 = Group.objects.create(groupname='test2', gid=1001)
|
group2 = Group.objects.create(groupname='test2', gid=1001)
|
||||||
|
@ -167,9 +171,9 @@ class GroupTest(TestCaseWithCeleryTasks):
|
||||||
self.assertEqual(len(Group.objects.all()), 1)
|
self.assertEqual(len(Group.objects.all()), 1)
|
||||||
group.delete()
|
group.delete()
|
||||||
self.assertEqual(len(Group.objects.all()), 0)
|
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()
|
tr = TaskResult.objects.first()
|
||||||
self.assertEqual(tr.task_name, 'delete_ldap_group')
|
self.assertEqual(tr.creator, 'handle_group_created')
|
||||||
|
|
||||||
|
|
||||||
class ShadowManagerTest(TestCaseWithCeleryTasks):
|
class ShadowManagerTest(TestCaseWithCeleryTasks):
|
||||||
|
@ -275,10 +279,12 @@ class UserManagerTest(TestCaseWithCeleryTasks):
|
||||||
def test_create_user_tasks(self):
|
def test_create_user_tasks(self):
|
||||||
User.objects.create_user(customer=self.customer)
|
User.objects.create_user(customer=self.customer)
|
||||||
taskres = TaskResult.objects.all()
|
taskres = TaskResult.objects.all()
|
||||||
self.assertEqual(len(taskres), 2)
|
self.assertEqual(len(taskres), 3)
|
||||||
tasknames = [r.task_name for r in taskres]
|
creators = [r.creator for r in taskres]
|
||||||
self.assertEqual(tasknames.count('setup_file_sftp_userdir'), 1)
|
for creator in [
|
||||||
self.assertEqual(tasknames.count('setup_file_mail_userdir'), 1)
|
'handle_group_created', 'handle_user_created',
|
||||||
|
'handle_user_password_set']:
|
||||||
|
self.assertIn(creator, creators)
|
||||||
|
|
||||||
def test_create_user_second(self):
|
def test_create_user_second(self):
|
||||||
User.objects.create_user(customer=self.customer)
|
User.objects.create_user(customer=self.customer)
|
||||||
|
@ -351,24 +357,26 @@ class UserTest(TestCaseWithCeleryTasks):
|
||||||
|
|
||||||
def test_save(self):
|
def test_save(self):
|
||||||
user = User.objects.create_user(self.customer)
|
user = User.objects.create_user(self.customer)
|
||||||
TaskResult.objects.all().delete()
|
|
||||||
user.save()
|
user.save()
|
||||||
taskres = TaskResult.objects.all()
|
taskres = TaskResult.objects.all()
|
||||||
self.assertEqual(len(taskres), 2)
|
self.assertEqual(len(taskres), 3)
|
||||||
task_names = [r.task_name for r in taskres]
|
creators = [r.creator for r in taskres]
|
||||||
self.assertIn('setup_file_sftp_userdir', task_names)
|
for task in [
|
||||||
self.assertIn('setup_file_mail_userdir', task_names)
|
'handle_group_created', 'handle_user_created',
|
||||||
|
'handle_user_password_set']:
|
||||||
|
self.assertIn(task, creators)
|
||||||
|
|
||||||
def test_delete_only_user(self):
|
def test_delete_only_user(self):
|
||||||
user = User.objects.create_user(self.customer)
|
user = User.objects.create_user(self.customer)
|
||||||
TaskResult.objects.all().delete()
|
|
||||||
user.delete()
|
user.delete()
|
||||||
taskres = TaskResult.objects.all()
|
taskres = TaskResult.objects.all()
|
||||||
self.assertEqual(len(taskres), 3)
|
self.assertEqual(len(taskres), 6)
|
||||||
tasknames = [r.task_name for r in taskres]
|
creators = [r.creator for r in taskres]
|
||||||
self.assertEqual(tasknames.count('delete_file_mail_userdir'), 1)
|
for task in [
|
||||||
self.assertEqual(tasknames.count('delete_file_sftp_userdir'), 1)
|
'handle_group_created', 'handle_user_created',
|
||||||
self.assertEqual(tasknames.count('delete_ldap_group'), 1)
|
'handle_user_password_set', 'handle_user_deleted',
|
||||||
|
'handle_group_deleted', 'handle_user_deleted']:
|
||||||
|
self.assertIn(task, creators)
|
||||||
self.assertEqual(len(User.objects.all()), 0)
|
self.assertEqual(len(User.objects.all()), 0)
|
||||||
|
|
||||||
def test_delete_additional_groups(self):
|
def test_delete_additional_groups(self):
|
||||||
|
@ -381,11 +389,12 @@ class UserTest(TestCaseWithCeleryTasks):
|
||||||
TaskResult.objects.all().delete()
|
TaskResult.objects.all().delete()
|
||||||
user.delete()
|
user.delete()
|
||||||
taskres = TaskResult.objects.all()
|
taskres = TaskResult.objects.all()
|
||||||
self.assertEqual(len(taskres), 3)
|
self.assertEqual(len(taskres), 5)
|
||||||
tasknames = [t.task_name for t in taskres]
|
creators = [t.creator for t in taskres]
|
||||||
self.assertEqual(tasknames.count('delete_file_mail_userdir'), 1)
|
for tcount, tcreator in [
|
||||||
self.assertEqual(tasknames.count('delete_file_sftp_userdir'), 1)
|
(2, 'handle_user_removed_from_group'), (2, 'handle_user_deleted'),
|
||||||
self.assertEqual(tasknames.count('delete_ldap_group'), 1)
|
(1, 'handle_group_deleted')]:
|
||||||
|
self.assertEqual(creators.count(tcreator), tcount)
|
||||||
self.assertEqual(len(User.objects.all()), 0)
|
self.assertEqual(len(User.objects.all()), 0)
|
||||||
self.assertEqual(len(AdditionalGroup.objects.all()), 0)
|
self.assertEqual(len(AdditionalGroup.objects.all()), 0)
|
||||||
|
|
||||||
|
@ -497,7 +506,7 @@ class SshPublicKeyTest(TestCaseWithCeleryTasks):
|
||||||
taskresults = TaskResult.objects.all()
|
taskresults = TaskResult.objects.all()
|
||||||
self.assertEqual(len(taskresults), 1)
|
self.assertEqual(len(taskresults), 1)
|
||||||
self.assertEqual(
|
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):
|
def test_call_tasks_on_delete(self):
|
||||||
key = SshPublicKey.objects.create_ssh_public_key(
|
key = SshPublicKey.objects.create_ssh_public_key(
|
||||||
|
@ -507,4 +516,4 @@ class SshPublicKeyTest(TestCaseWithCeleryTasks):
|
||||||
taskresults = TaskResult.objects.all()
|
taskresults = TaskResult.objects.all()
|
||||||
self.assertEqual(len(taskresults), 1)
|
self.assertEqual(len(taskresults), 1)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
taskresults[0].task_name, 'set_file_ssh_authorized_keys')
|
taskresults[0].creator, 'handle_ssh_keys_changed')
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('taskresults', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='taskresult',
|
||||||
|
name='task_name',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='taskresult',
|
||||||
|
name='creator',
|
||||||
|
field=models.TextField(default='migrated', verbose_name='Task creator'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='taskresult',
|
||||||
|
name='notes',
|
||||||
|
field=models.TextField(default='', verbose_name='Task notes'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='taskresult',
|
||||||
|
name='signature',
|
||||||
|
field=models.TextField(default='', verbose_name='Task signature'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
|
@ -12,15 +12,21 @@ from gnuviechadmin.celery import app
|
||||||
|
|
||||||
|
|
||||||
class TaskResultManager(models.Manager):
|
class TaskResultManager(models.Manager):
|
||||||
def create_task_result(self, asyncresult, name):
|
def create_task_result(self, creator, signature, notes=''):
|
||||||
taskresult = self.create(task_id=asyncresult.id, task_name=name)
|
sigstr = str(signature)
|
||||||
|
result = signature.apply_async()
|
||||||
|
taskresult = self.create(
|
||||||
|
task_id=result.task_id, creator=creator, signature=sigstr,
|
||||||
|
notes=notes)
|
||||||
return taskresult
|
return taskresult
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
@python_2_unicode_compatible
|
||||||
class TaskResult(models.Model):
|
class TaskResult(models.Model):
|
||||||
task_id = models.CharField(_('Task id'), max_length=36)
|
task_id = models.CharField(_('Task id'), max_length=36)
|
||||||
task_name = models.CharField(_('Task name'), max_length=64)
|
signature = models.TextField(_('Task signature'))
|
||||||
|
creator = models.TextField(_('Task creator'))
|
||||||
|
notes = models.TextField(_('Task notes'))
|
||||||
result = models.TextField(_('Task result'))
|
result = models.TextField(_('Task result'))
|
||||||
finished = models.BooleanField(default=False)
|
finished = models.BooleanField(default=False)
|
||||||
state = models.CharField(_('Task state'), max_length=16)
|
state = models.CharField(_('Task state'), max_length=16)
|
||||||
|
@ -32,8 +38,8 @@ class TaskResult(models.Model):
|
||||||
verbose_name_plural = _('Task results')
|
verbose_name_plural = _('Task results')
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "{task_name} ({task_id}): {finished}".format(
|
return "{creator} ({task_id}): {finished}".format(
|
||||||
task_name=self.task_name,
|
creator=self.creator,
|
||||||
task_id=self.task_id,
|
task_id=self.task_id,
|
||||||
finished=_('yes') if self.finished else _('no')
|
finished=_('yes') if self.finished else _('no')
|
||||||
)
|
)
|
||||||
|
@ -41,7 +47,8 @@ class TaskResult(models.Model):
|
||||||
def fetch_result(self):
|
def fetch_result(self):
|
||||||
if not self.finished:
|
if not self.finished:
|
||||||
ar = app.AsyncResult(self.task_id)
|
ar = app.AsyncResult(self.task_id)
|
||||||
res = ar.get(no_ack=True, timeout=1)
|
|
||||||
self.result = str(res)
|
|
||||||
self.state = ar.state
|
self.state = ar.state
|
||||||
|
if ar.ready():
|
||||||
|
res = ar.get()
|
||||||
|
self.result = str(res)
|
||||||
self.finished = True
|
self.finished = True
|
||||||
|
|
|
@ -13,24 +13,30 @@ TEST_TASK_RESULT = '4ll y0ur b453 4r3 b3l0ng t0 u5'
|
||||||
class TaskResultTest(TestCase):
|
class TaskResultTest(TestCase):
|
||||||
@patch('taskresults.models.app')
|
@patch('taskresults.models.app')
|
||||||
def test_update_taskstatus_unfinished(self, app):
|
def test_update_taskstatus_unfinished(self, app):
|
||||||
mock = MagicMock(id=TEST_TASK_UUID, task_name=TEST_TASK_NAME)
|
resultmock = MagicMock(task_id=TEST_TASK_UUID)
|
||||||
mock.ready.return_value = False
|
resultmock.ready.return_value = False
|
||||||
tr = TaskResult.objects.create_task_result(mock, TEST_TASK_NAME)
|
mock = MagicMock()
|
||||||
|
mock.apply_async.return_value = resultmock
|
||||||
|
tr = TaskResult.objects.create_task_result(TEST_TASK_NAME, mock)
|
||||||
self.assertFalse(tr.finished)
|
self.assertFalse(tr.finished)
|
||||||
mymock = app.AsyncResult(TEST_TASK_UUID)
|
mymock = app.AsyncResult(TEST_TASK_UUID)
|
||||||
mymock.state = 'SUCCESS'
|
mymock.state = 'SUCCESS'
|
||||||
mymock.get.return_value = TEST_RESULT
|
mymock.get.return_value = TEST_RESULT
|
||||||
tr.fetch_result()
|
tr.fetch_result()
|
||||||
mymock.get.assert_called_with(no_ack=True, timeout=1)
|
mymock.get.assert_called_with()
|
||||||
self.assertTrue(tr.finished)
|
self.assertTrue(tr.finished)
|
||||||
|
|
||||||
@patch('taskresults.models.app')
|
@patch('taskresults.models.app')
|
||||||
def test_update_taskstatus_finished(self, app):
|
def test_update_taskstatus_finished(self, app):
|
||||||
mock = MagicMock(id=TEST_TASK_UUID, task_name=TEST_TASK_NAME)
|
resultmock = MagicMock(task_id=TEST_TASK_UUID)
|
||||||
mock.ready.return_value = True
|
resultmock.ready.return_value = True
|
||||||
|
resultmock.state = 'SUCCESS'
|
||||||
|
resultmock.result = TEST_RESULT
|
||||||
|
mock = MagicMock()
|
||||||
|
mock.apply_async.return_value = resultmock
|
||||||
mock.state = 'SUCCESS'
|
mock.state = 'SUCCESS'
|
||||||
mock.result = TEST_RESULT
|
mock.result = TEST_RESULT
|
||||||
tr = TaskResult.objects.create_task_result(mock, TEST_TASK_NAME)
|
tr = TaskResult.objects.create_task_result(TEST_TASK_NAME, mock)
|
||||||
tr.fetch_result()
|
tr.fetch_result()
|
||||||
self.assertTrue(tr.finished)
|
self.assertTrue(tr.finished)
|
||||||
mymock = app.AsyncResult(TEST_TASK_UUID)
|
mymock = app.AsyncResult(TEST_TASK_UUID)
|
||||||
|
@ -47,8 +53,10 @@ TEST_RESULT.ready.return_value = False
|
||||||
|
|
||||||
class TaskResultManagerTest(TestCase):
|
class TaskResultManagerTest(TestCase):
|
||||||
def test_create_task_result(self):
|
def test_create_task_result(self):
|
||||||
mock = MagicMock(id=TEST_TASK_UUID)
|
resultmock = MagicMock(task_id=TEST_TASK_UUID)
|
||||||
tr = TaskResult.objects.create_task_result(mock, TEST_TASK_NAME)
|
mock = MagicMock()
|
||||||
|
mock.apply_async.return_value = resultmock
|
||||||
|
tr = TaskResult.objects.create_task_result(TEST_TASK_NAME, mock)
|
||||||
self.assertIsInstance(tr, TaskResult)
|
self.assertIsInstance(tr, TaskResult)
|
||||||
self.assertEqual(tr.task_id, TEST_TASK_UUID)
|
self.assertEqual(tr.task_id, TEST_TASK_UUID)
|
||||||
self.assertEqual(tr.task_name, TEST_TASK_NAME)
|
self.assertEqual(tr.creator, TEST_TASK_NAME)
|
||||||
|
|
Loading…
Reference in a new issue