Improve documentation

This commit adds a lot of documentation including block diagramms for
message flows.
This commit is contained in:
Jan Dittberner 2016-09-24 21:57:28 +02:00
parent 09cfc6a373
commit 5dc3549896
11 changed files with 853 additions and 87 deletions

View file

@ -31,6 +31,12 @@
.. automodule:: osusers.models .. automodule:: osusers.models
:members: :members:
:py:mod:`signals <osusers.signals>`
-----------------------------------
.. automodule:: osusers.signals
:members:
:py:mod:`urls <osusers.urls>` :py:mod:`urls <osusers.urls>`
----------------------------- -----------------------------

View file

@ -30,6 +30,12 @@
.. automodule:: userdbs.models .. automodule:: userdbs.models
:members: :members:
:py:mod:`signals <userdbs.signals>`
-----------------------------------
.. automodule:: userdbs.signals
:members:
:py:mod:`templatetags <userdbs.templatetags>` :py:mod:`templatetags <userdbs.templatetags>`
--------------------------------------------- ---------------------------------------------

View file

@ -33,12 +33,17 @@ django.setup()
# Add any Sphinx extension module names here, as strings. They can be extensions # Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['releases', 'sphinx.ext.autodoc', 'celery.contrib.sphinx'] extensions = [
'releases', 'sphinx.ext.autodoc', 'celery.contrib.sphinx',
'sphinxcontrib.blockdiag']
# configuration for releases extension # configuration for releases extension
releases_issue_uri = 'https://dev.gnuviech-server.de/gva/ticket/%s' releases_issue_uri = 'https://dev.gnuviech-server.de/gva/ticket/%s'
releases_release_uri = 'https://dev.gnuviech-server.de/gva/browser/?rev=%s' releases_release_uri = 'https://dev.gnuviech-server.de/gva/browser/?rev=%s'
# configuration for blockdiag extension
blockdiag_fontpath = '/usr/share/fonts/truetype/dejavu/'
# Add any paths that contain templates here, relative to this directory. # Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates'] templates_path = ['_templates']

View file

@ -9,6 +9,20 @@ Welcome to gnuviechadmin's documentation!
.. include:: ../README.rst .. include:: ../README.rst
Contents
--------
.. toctree::
:maxdepth: 3
install
deploy
tests
code
ideas
task_flows
changelog
License License
------- -------
@ -20,19 +34,6 @@ later version.
.. include:: ../COPYING .. include:: ../COPYING
:literal: :literal:
Contents
--------
.. toctree::
:maxdepth: 2
install
deploy
tests
code
ideas
changelog
Indices and tables Indices and tables
------------------ ------------------

35
docs/task_flows.rst Normal file
View file

@ -0,0 +1,35 @@
**********
Task Flows
**********
gva uses Celery tasks to trigger actions on several servers, this chapter lists
the code parts that start tasks. See the code documentation for details on the
information flow.
:py:mod:`osusers.admin`
=======================
* :py:meth:`osusers.admin.SshPublicKeyAdmin.perform_delete_selected`
:py:mod:`osusers.signals`
=========================
* :py:func:`osusers.signals.handle_group_created`
* :py:func:`osusers.signals.handle_group_deleted`
* :py:func:`osusers.signals.handle_ssh_keys_changed`
* :py:func:`osusers.signals.handle_user_added_to_group`
* :py:func:`osusers.signals.handle_user_created`
* :py:func:`osusers.signals.handle_user_deleted`
* :py:func:`osusers.signals.handle_user_password_set`
* :py:func:`osusers.signals.handle_user_removed_from_group`
:py:mod:`userdbs.signals`
=========================
* :py:func:`userdbs.signals.handle_dbuser_created`
* :py:func:`userdbs.signals.handle_dbuser_deleted`
* :py:func:`userdbs.signals.handle_dbuser_deleted`
* :py:func:`userdbs.signals.handle_dbuser_password_set`
* :py:func:`userdbs.signals.handle_userdb_created`

View file

@ -14,10 +14,38 @@ 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.
:param str username: the user name :param str username: the username
:raises Exception: if the SFTP directory of the user cannot be created :raises Exception: if the SFTP directory of the user cannot be created
:return: the created directory name :return: a dictionary with the key :py:const:`username` set to the
:rtype: str username value and a new key :py:const:`sftp_directory` set to the
path of the created SFTP directory
:rtype: dict
.. note::
This variant can only be used at the beginning of a Celery task chain
or as a standalone task.
Use :py:func:`fileservertasks.tasks.setup_file_sftp_userdir_chained`
at other positions in the task chain.
"""
@shared_task
def setup_file_sftp_userdir_chained(previous_result, *args, **kwargs):
"""
This task creates the home directory for an SFTP user if it does not exist
yet.
:param dict previous_result: a dictionary describing the result of the
previous step in the Celery task chain. This dictionary must contain a
:py:const:`username` key
:raises Exception: if the SFTP directory of the user cannot be created
:return: a copy of the :py:obj:`previous_result` dictionary with a new
:py:const:`sftp_directory` key set to the path of the created SFTP
directory
:rtype: dict
""" """
@ -26,12 +54,40 @@ def setup_file_sftp_userdir(username, *args, **kwargs):
def delete_file_sftp_userdir(username, *args, **kwargs): 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. exists.
:param str username: the user name :param str username: the username
:raises Exception: if the SFTP directory of the user cannot be removed :raises Exception: if the SFTP directory of the user cannot be removed
:return: the removed directory name :return: a dictionary with the key :py:const:`username` set to the username
:rtype: str value and the new key :py:const:`sftp_directory` set to the path of the
deleted SFTP directory
:rtype: dict
.. note::
This variant can only be used at the beginning of a Celery task chain
or as a standalone task.
Use :py:func:`fileservertasks.tasks.delete_file_sftp_userdir_chained`
at other positions in the task chain.
"""
@shared_task
def delete_file_sftp_userdir_chained(previous_result, *args, **kwargs):
"""
This task recursively deletes the home directory of an SFTP user if it
exists.
:param dict previous_result: a dictionary describing the result of the
previous step in the Celery task chain. This dictionary must contain a
:py:const:`username` key
:raises Exception: if the SFTP directory of the user cannot be removed
:return: a copy of the :py:obj:`previous_result` dictionary with a new
:py:const:`sftp_directory` key set to the path of the removed SFTP
directory
:rtype: dict
""" """
@ -42,11 +98,40 @@ 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.
:param str username: the user name :param str username: the username
:raises Exception: if the mail base directory for the user cannot be :raises Exception: if the mail base directory for the user cannot be
created created
:return: the created directory name :return: a dictionary with the key :py:const:`username` set to the
:rtype: str username value and a new key :py:const:`mail_directory` set to the path
of the created mail directory
:rtype: dict
.. note::
This variant can only be used at the beginning of a Celery task chain
or as a standalone task.
Use :py:func:`fileservertasks.tasks.setup_file_mail_userdir_chained`
at other positions in the task chain.
"""
@shared_task
def setup_file_mail_userdir_chained(previous_result, *args, **kwargs):
"""
This task creates the mail base directory for a user if it does not exist
yet.
:param dict previous_result: a dictionary containing the result of the
previous step in the Celery task chain. This dictionary must contain a
:py:const:`username` key
:raises Exception: if the mail base directory for the user cannot be
created
:return: a copy of the :py:obj:`previous_result` dictionary with a new
:py:const:`mail_directory` key set to the path of the created mail
directory
:rtype: dict
""" """
@ -57,79 +142,255 @@ 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.
:param str username: the user name :param str username: the username
:raises Exception: if the mail base directory of the user cannot be removed :raises Exception: if the mail base directory of the user cannot be deleted
:return: the removed directory name :return: a dictionary with the key :py:const:`username` set to the
username value and a new key :py:const:`mail_directory` set to the path
of the deleted mail directory
:rtype: dict
.. note::
This variant can only be used at the beginning of a Celery task chain
or as a standalone task.
Use :py:func:`fileservertasks.tasks.delete_file_mail_userdir_chained`
at other positions in the task chain.
"""
@shared_task
def delete_file_mail_userdir_chained(previous_result, *args, **kwargs):
"""
This task recursively deletes the mail base directory for a user if it
does not exist yet.
:param dict previous_result: a dictionary describing the result of the
previous step in the Celery task chain. This dictionary must contain a
:py:const:`username` key
:raises Exception: if the mail base directory of the user cannot be deleted
:return: a copy of the :py:obj:`previous_result` dictionary with a new
:py:const:`mail_directory` key set to the path of the deleted mail
directory
:rtype: str :rtype: str
""" """
@shared_task @shared_task
def create_file_mailbox(username, mailboxname): def create_file_mailbox(username, mailboxname, *args, **kwargs):
""" """
This task creates a new mailbox directory for the given user and mailbox This task creates a new mailbox directory for the given user and mailbox
name. name.
:param str username: the user name :param str username: the username
:param str mailboxname: the mailbox name :param str mailboxname: the mailbox name
:raises Exception: if the mailbox directory cannot be created :raises Exception: if the mailbox directory cannot be created
:return: the created mailbox directory name :return: a dictionary with the keys :py:const:`username` and
:rtype: str :py:const:`mailboxname` set to the values of username and mailboxname
and a new key :py:const:`mailbox_directory` set to the path of the
created mailbox directory
:rtype: dict
.. note::
This variant can only be used at the beginning of a Celery task chain
or as a standalone task.
Use :py:func:`fileservertasks.tasks.create_file_mailbox_chained` at
other positions in the task chain.
""" """
@shared_task @shared_task
def delete_file_mailbox(username, mailboxname): def create_file_mailbox_chained(previous_result, *args, **kwargs):
"""
This task creates a new mailbox directory for the given user and mailbox
name.
:param dict previous_result: a dictionary describing the result of the
previous step in the Celery task chain. This dictionary must contain a
:py:const:`username` and a :py:const:`mailboxname` key
:raises Exception: if the mailbox directory cannot be created
:return: a copy of the :py:obj:`previous_result` dictionary with a new
:py:const:`mailbox_directory` key set to the path of the created
mailbox directory
:rtype: dict
"""
@shared_task
def delete_file_mailbox(username, mailboxname, *args, **kwargs):
""" """
This task deletes the given mailbox of the given user. This task deletes the given mailbox of the given user.
:param str username: the user name :param str username: the username
:param str mailboxname: the mailbox name :param str mailboxname: the mailbox name
:raises Exception: if the mailbox directory cannot be deleted :raises Exception: if the mailbox directory cannot be deleted
:return: the deleted mailbox directory name :return: a dictionary with the keys :py:const:`username` and
:rtype: str :py:const:`mailboxname` set to the values of username and mailboxname
and a new key :py:const:`mailbox_directory` set to the path of the
deleted mailbox directory
:rtype: dict
.. note::
This variant can only be used at the beginning of a Celery task chain
or as a standalone task.
Use :py:func:`fileservertasks.tasks.delete_file_mailbox_chained` for
other positions in the task chain.
""" """
@shared_task @shared_task
def create_file_website_hierarchy(username, sitename): def delete_file_mailbox_chained(previous_result, *args, **kwargs):
"""
This task deletes the given mailbox of the given user.
:param dict previous_result: a dictionary describing the result of the
previous step in the Celery task chain. This dictionary must contain a
:py:const:`username` and a :py:const:`mailboxname` key
:raises Exception: if the mailbox directory cannot be deleted
:return: a copy of the :py:obj:`previous_result` dictionary with a new
:py:const:`mailbox_directory` key set to the path of the deleted
mailbox directory
:rtype: dict
"""
@shared_task
def create_file_website_hierarchy(username, sitename, *args, **kwargs):
""" """
This task creates the directory hierarchy for a website. This task creates the directory hierarchy for a website.
:param str username: the user name :param str username: the username
:param str sitename: name of the website :param str sitename: the sitename
:return: the directory name :raises Exception: if the website directory hierarchy directory cannot be
:rtype: str created
:return: a dictionary with the keys :py:const:`username` and
:py:const:`sitename` set to the values of username and sitename and a
new key :py:const:`website_directory` set to the path of the created
website directory
:rtype: dict
.. note::
This variant can only be used at the beginning of a Celery task chain
or as a standalone task.
Use
:py:func:`fileservertasks.tasks.create_file_website_hierarchy_chained`
at other positions in the task chain
""" """
@shared_task @shared_task
def delete_file_website_hierarchy(username, sitename): def create_file_website_hierarchy_chained(previous_result, *args, **kwargs):
"""
This task creates the directory hierarchy for a website.
:param dict previous_result: a dictionary describing the result of the
previous step in the Celery task chain. This dictionary must contain a
:py:const:`username` and a :py:const:`sitename` key
:raises Exception: if the website directory hierarchy directory cannot be
created
:return: a copy of the :py:obj:`previous_result` dictionary with a new
:py:const:`website_directory` key set to the path of the created
website directory
:rtype: dict
"""
@shared_task
def delete_file_website_hierarchy(username, sitename, *args, **kwargs):
"""
This task deletes a website hierarchy recursively.
:param str username: a username
:param str sitename: a site name
:return: a dictionary with the keys :py:const:`username` and
:py:const:`sitename` set to their original values and a new key
:py:const:`website_directory` set to the path of the deleted website
:rtype: dict
.. note::
This variant can only be used at the beginning of a Celery task chain
or as a standalone task.
Use
:py:func:`fileservertasks.tasks.delete_file_website_hierarchy_chained`
at other positions in the task chain
"""
@shared_task
def delete_file_website_hierarchy_chained(previous_result, *args, **kwargs):
""" """
This task deletes the website hierarchy recursively. This task deletes the website hierarchy recursively.
:param str username: the user name :param dict previous_result: a dictionary describing the result of the
:param str sitename: name of the website previous step in the Celery task chain. This dictionary must contain a
:return: the directory name :py:const:`username` and a :py:const:`sitename` key
:rtype: str :raises Exception: if the website directory hierarchy directory cannot be
deleted
:return: a copy of the :py:obj:`previous_result` dictionary with a new
:py:const:`website_directory` set to the path of the deleted website
directory
:rtype: dict
""" """
@shared_task @shared_task
def set_file_ssh_authorized_keys(username, ssh_keys): def set_file_ssh_authorized_keys(username, ssh_keys, *args, **kwargs):
"""
This task set the authorized keys for ssh logins.
:param str username: a username
:param list ssh_keys: a list of ssh keys
:raises Exception: if the update of the creation or update of ssh
authorized_keys failed
:return: a dictionary with the keys :py:const:`username` and
:py:const:`ssh_keys` set to their original values and a new key
:py:const:`ssh_authorized_keys` set to the path of the SSH
authorized_keys file
:rtype: dict
.. note::
This variant can only be used at the beginning of a Celery task chain
or as a standalone task.
Use
:py:func:`fileservertasks.tasks.set_file_ssh_authorized_keys_chained`
at other positions in the task chain
"""
@shared_task
def set_file_ssh_authorized_keys_chained(previous_result, *args, **kwargs):
""" """
This task sets the authorized keys for ssh logins. This task sets the authorized keys for ssh logins.
:param str username: the user name :param dict previous_result: a dictionary describing the result of the
:param list ssh_key: an ssh_key previous step in the Celery task chain. This dictionary must contain a
:py:const:`username` and a :py:const:`ssh_keys` key
:raises Exception: if the update of the creation or update of ssh :raises Exception: if the update of the creation or update of ssh
authorized_keys failed authorized_keys failed
:return: the name of the authorized_keys file :return: a copy of the :py:obj:`previous_result` dictionary with a new
:rtype: str :py:const:`ssh_authorized_keys` set to the path of the SSH
authorized_keys file
:rtype: dict
""" """

View file

@ -9,7 +9,7 @@ from celery import shared_task
@shared_task @shared_task
def create_ldap_group(groupname, gid, descr): def create_ldap_group(groupname, gid, description):
""" """
This task creates an :py:class:`LDAP group <ldapentities.models.LdapGroup>` This task creates an :py:class:`LDAP group <ldapentities.models.LdapGroup>`
if it does not exist yet. if it does not exist yet.
@ -19,9 +19,12 @@ def create_ldap_group(groupname, gid, descr):
:param str groupname: the group name :param str groupname: the group name
:param int gid: the group id :param int gid: the group id
:param str descr: description text for the group :param str description: description text for the group
:return: the distinguished name of the group :return: dictionary containing groupname, gid, description and
:rtype: str :py:const:`group_dn` set to the distinguished name of the newly created
or existing LDAP group
:rtype: dict
""" """
@ -45,8 +48,10 @@ def create_ldap_user(username, uid, gid, gecos, homedir, shell, password):
is passed the password is not touched is passed the password is not touched
:raises celery.exceptions.Reject: if the specified primary group does not :raises celery.exceptions.Reject: if the specified primary group does not
exist exist
:return: the distinguished name of the user :return: dictionary containing username, uid, gid, gecos, homedir, shell,
:rtype: str password and :py:const:`user_dn` set to the distinguished name of the
newly created or existing LDAP user
:rtype: dict
""" """
@ -59,8 +64,10 @@ def set_ldap_user_password(username, password):
:param str username: the user name :param str username: the user name
:param str password: teh clear text password :param str password: teh clear text password
:return: :py:const:`True` if the password has been set, :py:const:`False` :return: dictionary containing the username and a flag
if the user does not exist. :py:const:`password_set` that is set to :py:const:`True` if the
password has been set, :py:const:`False` if the user does not exist.
:rtype: dict
""" """
@ -76,8 +83,10 @@ def add_ldap_user_to_group(username, groupname):
:param str groupname: the group name :param str groupname: the group name
:raises celery.exceptions.Retry: if the user does not exist yet, :raises celery.exceptions.Retry: if the user does not exist yet,
:py:func:`create_ldap_user` should be called before :py:func:`create_ldap_user` should be called before
:return: True if the user has been added to the group otherwise False :return: dictionary containing the username, groupname and a flag
:rtype: boolean :py:const`added` that is as a :py:const:`True` if the user has been
added to the group otherwise to :py:const:`False`
:rtype: dict
""" """
@ -89,20 +98,48 @@ def remove_ldap_user_from_group(username, groupname):
:param str username: the user name :param str username: the user name
:param str groupname: the group name :param str groupname: the group name
:return: True if the user has been removed, False otherwise :return: dictionary containing the input parameters and a flag
:rtype: boolean :py:const:`removed` that is set to :py:const:`True` if the user has
been removed, False otherwise
:rtype: dict
""" """
@shared_task @shared_task
def delete_ldap_user(username): def delete_ldap_user(username, *args, **kwargs):
""" """
This task deletes the given user. This task deletes the given user.
:param str username: the user name :param str username: the user name
:return: True if the user has been deleted, False otherwise :return: dictionary containing the username and a flag :py:const:`deleted`
:rtype: boolean that is set to :py:const:`True` if the user has been deleted and is set
to :py:const:`False` otherwise
:rtype: dict
.. note::
This variant can only be used at the beginning of a Celery task chain
or as a standalone task.
Use :py:func:`ldaptasks.tasks.delete_ldap_user_chained` at other
positions in the task chain
"""
@shared_task
def delete_ldap_user_chained(previous_result, *args, **kwargs):
"""
This task deletes the given user.
:param dict previous_result: a dictionary describing the result of the
previous step in the Celery task chain. This dictionary must contain a
:py:const:`username` key
:return: a copy of the :py:obj:`previous_result` dictionary with a new
:py:const:`deleted` key set to :py:const:`True` if the user has been
deleted and set to :py:const:`False` otherwise
:rtype: dict
""" """
@ -113,8 +150,10 @@ def delete_ldap_group_if_empty(groupname):
This task deletes the given group if it is empty. This task deletes the given group if it is empty.
:param str groupname: the group name :param str groupname: the group name
:return: True if the user has been deleted, False otherwise :return: dictionary that contains the groupname and a flag
:rtype: boolean :py:const:`deleted` that is set to :py:const:`True` if the group has
been deleted and is set to :py:const:`False` otherwise
:rtype: dict
""" """
@ -122,10 +161,12 @@ def delete_ldap_group_if_empty(groupname):
@shared_task @shared_task
def delete_ldap_group(groupname): def delete_ldap_group(groupname):
""" """
This taks deletes the given group. This task deletes the given group.
:param str groupname: the group name :param str groupname: the group name
:return: True if the user has been deleted, False otherwise :return: dictionary that contains the groupname and a flag
:rtype: boolean :py:const:`deleted` that is set to :py:const:`True` if the group has
been deleted and is set to :py:const:`False` otherwise
:rtype: dict
""" """

View file

@ -1,6 +1,10 @@
""" """
This module contains the Django admin classes of the :py:mod:`osusers` app. This module contains the Django admin classes of the :py:mod:`osusers` app.
The module starts Celery_ tasks.
.. _Celery: http://www.celeryproject.org/
""" """
from django import forms from django import forms
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -341,6 +345,30 @@ class SshPublicKeyAdmin(admin.ModelAdmin):
:param request: the current HTTP request :param request: the current HTTP request
:param queryset: Django ORM queryset representing the selected ssh keys :param queryset: Django ORM queryset representing the selected ssh keys
This method starts a Celery_ task to update the list of authorized keys
for each affected user.
.. blockdiag::
:desctable:
blockdiag {
node_width = 200;
A -> B;
A [ label = "", shape = beginpoint,
description = "this method"
];
B [ label = "set file ssh authorized_keys",
description = ":py:func:`set_file_ssh_authorized_keys()
<fileservertasks.tasks.set_file_ssh_authorized_keys>`
called with username and a list of keys, returning the path
of the ssh authorized_keys file",
color = "LightGreen",
stacked
];
}
""" """
users = set([ users = set([
item['user'] for item in item['user'] for item in

View file

@ -1,6 +1,10 @@
""" """
This module contains the signal handlers of the :py:mod:`osusers` app. This module contains the signal handlers of the :py:mod:`osusers` app.
The module starts Celery_ tasks.
.. _Celery: http://www.celeryproject.org/
""" """
from __future__ import absolute_import, unicode_literals from __future__ import absolute_import, unicode_literals
@ -14,17 +18,17 @@ from django.dispatch import receiver
from fileservertasks.tasks import ( from fileservertasks.tasks import (
delete_file_mail_userdir, delete_file_mail_userdir,
delete_file_sftp_userdir, delete_file_sftp_userdir_chained,
set_file_ssh_authorized_keys, set_file_ssh_authorized_keys,
setup_file_mail_userdir, setup_file_mail_userdir_chained,
setup_file_sftp_userdir, setup_file_sftp_userdir_chained,
) )
from ldaptasks.tasks import ( from ldaptasks.tasks import (
add_ldap_user_to_group, add_ldap_user_to_group,
create_ldap_group, create_ldap_group,
create_ldap_user, create_ldap_user,
delete_ldap_group, delete_ldap_group,
delete_ldap_user, delete_ldap_user_chained,
remove_ldap_user_from_group, remove_ldap_user_from_group,
set_ldap_user_password, set_ldap_user_password,
) )
@ -44,6 +48,33 @@ _LOGGER = logging.getLogger(__name__)
@receiver(password_set, sender=User) @receiver(password_set, sender=User)
def handle_user_password_set(sender, instance, password, **kwargs): def handle_user_password_set(sender, instance, password, **kwargs):
"""
Handles password changes on :py:class:`User <osusers.models.User>`
instances.
:param sender: sender of the signal
:param instance: User instance
:param str password: the new password
This signal handler starts a Celery_ task.
.. blockdiag::
:desctable:
blockdiag {
node_width = 200;
A -> B;
A [ label = "", shape = beginpoint,
description = "this signal handler" ];
B [ label = "set ldap user password", color = "Wheat",
description = ":py:func:`set_ldap_user_password()
<ldaptasks.tasks.set_ldap_user_password>` called with
username and password, returning :py:const:`True` if the
password has been set" ];
}
"""
taskresult = TaskResult.objects.create_task_result( taskresult = TaskResult.objects.create_task_result(
'handle_user_password_set', 'handle_user_password_set',
set_ldap_user_password.s(instance.username, password)) set_ldap_user_password.s(instance.username, password))
@ -52,15 +83,35 @@ def handle_user_password_set(sender, instance, password, **kwargs):
taskresult.task_id) 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) @receiver(post_save, sender=Group)
def handle_group_created(sender, instance, created, **kwargs): def handle_group_created(sender, instance, created, **kwargs):
"""
Handles post creation actions on :py:class:`Group <osusers.models.Group>`
instances.
:param sender: sender of the signal
:param instance: Group instance
:param bool created: whether the instance has just been created
This signal handler starts a Celery_ task.
.. blockdiag::
:desctable:
blockdiag {
node_width = 200;
A -> B;
A [ label = "", shape = beginpoint,
description = "this signal handler" ];
B [ label = "create ldap group", color = "Wheat",
description = ":py:func:`create_ldap_group()
<ldaptasks.tasks.create_ldap_group>` called with groupname,
gid and description, returning group DN" ];
}
"""
if created: if created:
taskresult = TaskResult.objects.create_task_result( taskresult = TaskResult.objects.create_task_result(
'handle_group_created', 'handle_group_created',
@ -75,13 +126,52 @@ def handle_group_created(sender, instance, created, **kwargs):
@receiver(post_save, sender=User) @receiver(post_save, sender=User)
def handle_user_created(sender, instance, created, **kwargs): def handle_user_created(sender, instance, created, **kwargs):
"""
Handles post creation actions on :py:class:`User <osusers.models.User>`
instances.
:param sender: sender of the signal
:param instance: User instance
:param bool created: whether the instance has just bean created
This signal handler starts a chain of Celery_ tasks.
.. blockdiag::
:desctable:
blockdiag {
node_width = 200;
A -> B -> C -> D;
B -> C [folded];
A [ label = "", shape = beginpoint,
description = "this signal handler" ];
B [ label = "create ldap user", color = "Wheat",
description = ":py:func:`create_ldap_user()
<ldaptasks.tasks.create_ldap_user>` called with username, uid,
gid, gecos, homeidr, shell, :py:const:`None`, returning
username" ];
C [ label = "setup file sftp userdir", color = "LightGreen",
description = ":py:func:`setup_file_sftp_userdir_chained()
<fileservertasks.tasks.setup_file_sftp_userdir_chained>`
called with the result of create ldap user task, returning a
dictionary containing username and sftp_directory"];
D [ label = "setup file mail userdir", color = "LightGreen",
description = ":py:func:`setup_file_mail_userdir_chained()
<fileservertasks.tasks.setup_file_mail_userdir_chained>` called
with result of setup file sftp userdir task, returning
dictionary containing username, sftp_directory and
mail_directory" ];
}
"""
if created: if created:
chain = create_ldap_user.s( chain = create_ldap_user.s(
instance.username, instance.uid, instance.group.gid, instance.username, instance.uid, instance.group.gid,
instance.gecos, instance.homedir, instance.shell, None instance.gecos, instance.homedir, instance.shell, None
) | setup_file_sftp_userdir.s( ) | setup_file_sftp_userdir_chained.s() | (
instance.username setup_file_mail_userdir_chained.s())
) | setup_file_mail_userdir.s(instance.username)
taskresult = TaskResult.objects.create_task_result( taskresult = TaskResult.objects.create_task_result(
'handle_user_created', chain) 'handle_user_created', chain)
_LOGGER.info( _LOGGER.info(
@ -93,6 +183,34 @@ def handle_user_created(sender, instance, created, **kwargs):
@receiver(post_save, sender=AdditionalGroup) @receiver(post_save, sender=AdditionalGroup)
def handle_user_added_to_group(sender, instance, created, **kwargs): def handle_user_added_to_group(sender, instance, created, **kwargs):
"""
Handles post creation actions on :py:class:`AdditionalGroup
<osusers.models.AdditionalGroup>` instances.
:param sender: sender of the signal
:param instance: AdditionalGroup instance
:param bool created: whether the instance has just bean created
This signal handler starts a Celery_ task.
.. blockdiag::
:desctable:
blockdiag {
node_width = 200;
A -> B;
A [ label = "", shape = beginpoint,
description = "this signal handler" ];
B [ label = "add ldap user to group", color = "Wheat",
description = ":py:func:`add_ldap_user_to_group()
<ldaptasks.tasks.add_ldap_user_to_group>` called with username
and groupname, returning :py:const:`True` if the user has been
added to the group" ];
}
"""
if created: if created:
taskresult = TaskResult.objects.create_task_result( taskresult = TaskResult.objects.create_task_result(
'handle_user_added_to_group', 'handle_user_added_to_group',
@ -106,6 +224,33 @@ def handle_user_added_to_group(sender, instance, created, **kwargs):
@receiver(post_save, sender=SshPublicKey) @receiver(post_save, sender=SshPublicKey)
@receiver(post_delete, sender=SshPublicKey) @receiver(post_delete, sender=SshPublicKey)
def handle_ssh_keys_changed(sender, instance, **kwargs): def handle_ssh_keys_changed(sender, instance, **kwargs):
"""
Handles changes to :py:class:`SshPublicKey <osuses.models.SshPublicKey>`
instances related to a user.
:param sender: sender of the signal
:param instance: SshPublicKey instance
This signal handler starts a Celery_ task.
.. blockdiag::
:desctable:
blockdiag {
node_width = 200;
A -> B;
A [ label = "", shape = beginpoint,
description = "this signal handler" ];
B [ label = "set file ssh authorized_keys", color = "LightGreen",
description = ":py:func:`set_file_ssh_authorized_keys()
<fileservertasks.tasks.set_file_ssh_authorized_keys>` called
with username and the corresponding list of keys, returning the
path of the ssh_authorized_keys_file" ];
}
"""
sig = set_file_ssh_authorized_keys.s( sig = set_file_ssh_authorized_keys.s(
instance.user.username, [ instance.user.username, [
str(key) for key in str(key) for key in
@ -126,6 +271,33 @@ def handle_ssh_keys_changed(sender, instance, **kwargs):
@receiver(post_delete, sender=Group) @receiver(post_delete, sender=Group)
def handle_group_deleted(sender, instance, **kwargs): def handle_group_deleted(sender, instance, **kwargs):
"""
Handles cleanup actions to be done after deletion of a :py:class:`Group
<osusers.models.Group>` instance.
:param sender: sender of the signal
:param instance: Group instance
This signal handler starts a Celery_ task.
.. blockdiag::
:desctable:
blockdiag {
node_width = 200;
A -> B;
A [ label = "", shape = beginpoint,
description = "this signal handler"
];
B [ label = "delete ldap group", color = "Wheat",
description = ":py:func:`delete_ldap_group()
<ldaptasks.tasks.delete_ldap_group>` called with groupname,
returning :py:const:`True` if the group has been deleted" ];
}
"""
taskresult = TaskResult.objects.create_task_result( taskresult = TaskResult.objects.create_task_result(
'handle_group_deleted', 'handle_group_deleted',
delete_ldap_group.s(instance.groupname)) delete_ldap_group.s(instance.groupname))
@ -136,11 +308,49 @@ def handle_group_deleted(sender, instance, **kwargs):
@receiver(post_delete, sender=User) @receiver(post_delete, sender=User)
def handle_user_deleted(sender, instance, **kwargs): def handle_user_deleted(sender, instance, **kwargs):
"""
Handles cleanup actions to be done after deletion of a :py:class:`User
<osusers.models.User>` instance.
:param sender: sender of the signal
:param instance: User instance
This signal handler starts a chain of Celery_ tasks.
.. blockdiag::
:desctable:
blockdiag {
node_width = 200;
A -> B -> C -> D;
B -> C [folded];
A [ label = "", shape = beginpoint,
description = "this signal handler"
];
B [ label = "delete file mail userdir", color = "LightGreen",
description = ":py:func:`delete_file_mail_userdir()
<fileservertasks.tasks.delete_file_mail_userdir>` called with
username, returning a dictionary containing the username and
the deleted mail_directory" ];
C [ label = "delete file sftp userdir", color = "LightGreen",
description = ":py:func:`delete_file_sftp_userdir_chained()
<fileservertasks.tasks.delete_file_sftp_userdir_chained>`
called with the result of delete mail userdir, returning
dictionary containing username, deleted mail_directory and
deleted sftp_directory" ];
D [ label = "delete ldap user", color = "Wheat",
description = ":py:func:`delete_ldap_user_chained()
<ldaptasks.tasks.delete_ldap_user_chained>` called with the
result of delete file sftp userdir and adding the deleted user
DN to the result" ];
}
"""
chain = delete_file_mail_userdir.s( chain = delete_file_mail_userdir.s(
instance.username instance.username
) | delete_file_sftp_userdir.s( ) | delete_file_sftp_userdir_chained.s() | delete_ldap_user_chained.s()
instance.username
) | delete_ldap_user.s(instance.username)
_LOGGER.debug('chain signature %s', chain) _LOGGER.debug('chain signature %s', chain)
taskresult = TaskResult.objects.create_task_result( taskresult = TaskResult.objects.create_task_result(
'handle_user_deleted', chain) 'handle_user_deleted', chain)
@ -151,6 +361,37 @@ def handle_user_deleted(sender, instance, **kwargs):
@receiver(post_delete, sender=AdditionalGroup) @receiver(post_delete, sender=AdditionalGroup)
def handle_user_removed_from_group(sender, instance, **kwargs): def handle_user_removed_from_group(sender, instance, **kwargs):
"""
Handles cleanup actions to be done after removing a user from a group by
deleting the :py:class:`AdditionalGroup <osusers.models.AdditionalGroup>`
instance.
:param sender: sender of the signal
:param instance: AdditionalGroup instance
This signal handler starts a Celery_ task.
.. blockdiag::
:desctable:
blockdiag {
node_width = 200;
A -> B;
A [ label = "", shape = beginpoint,
description = "this signal handler"
];
B [ label = "remove ldap user from group", color = "Wheat",
description = ":py:func:`remove_ldap_user_from_group()
<ldaptasks.tasks.remove_ldap_user_from_group>` called with
username and groupname, returning :py:const:`True` if the user
has been a member of the group and has been removed from the
group"
];
}
"""
taskresult = TaskResult.objects.create_task_result( taskresult = TaskResult.objects.create_task_result(
'handle_user_removed_from_group', 'handle_user_removed_from_group',
remove_ldap_user_from_group.s( remove_ldap_user_from_group.s(

View file

@ -1,6 +1,10 @@
""" """
This module contains the signal handlers of the :py:mod:`userdbs` app. This module contains the signal handlers of the :py:mod:`userdbs` app.
The module starts Celery_ tasks.
.. _Celery: http://www.celeryproject.org/
""" """
from __future__ import unicode_literals from __future__ import unicode_literals
@ -29,6 +33,34 @@ def handle_dbuser_password_set(sender, instance, password, **kwargs):
Signal handler triggered by password changes for Signal handler triggered by password changes for
:py:class:`userdbs.models.DatabaseUser` instances. :py:class:`userdbs.models.DatabaseUser` instances.
:param sender: the sender of the signal
:param instance: the Database user instance
:param str password: the new password for the database user
This signal handler starts Celery_ tasks depending on the db_type value of
the database user.
.. blockdiag::
:desctable:
blockdiag {
node_width = 200;
A -> B;
A -> C;
A [ label = "", shape = beginpoint,
description = "this signal handler" ];
B [ label = "set mysql userpassword", color = "PowderBlue",
description = ":py:func:`set_mysql_userpassword()
<mysqltasks.tasks.set_mysql_userpassword>` called with
database username and password" ];
C [ label = "set pgsql userpassword", color = "DodgerBlue",
description = ":py:func:`set_pgsql_userpassword()
<pgsqltasks.tasks.set_pgsql_userpassword>` called with
database username and password" ];
}
""" """
if instance.db_type == DB_TYPES.mysql: if instance.db_type == DB_TYPES.mysql:
taskresult = TaskResult.objects.create_task_result( taskresult = TaskResult.objects.create_task_result(
@ -59,6 +91,35 @@ def handle_dbuser_created(sender, instance, created, **kwargs):
Signal handler triggered after the creation of or updates to Signal handler triggered after the creation of or updates to
:py:class:`userdbs.models.DatabaseUser` instances. :py:class:`userdbs.models.DatabaseUser` instances.
:param sender: the sender of the signal
:param instance: the DatabaseUser instance
:param bool created: whether this signal handler is called for a newly
created instance
This signal handler starts Celery_ tasks depending on the db_type value of
the database user.
.. blockdiag::
:desctable:
blockdiag {
node_width = 200;
A -> B;
A -> C;
A [ label = "", shape = beginpoint,
description = "this signal handler" ];
B [ label = "create mysql user", color = "PowderBlue",
description = ":py:func:`create_mysql_user()
<mysqltasks.tasks.create_mysql_user>` called with database
username and password" ];
C [ label = "create pgsql user", color = "DodgerBlue",
description = ":py:func:`create_pgsql_user
<pgsqltasks.tasks.create_pgsql_user>` called with database
username and password" ];
}
""" """
if created: if created:
password = kwargs.get('password', generate_password()) password = kwargs.get('password', generate_password())
@ -95,6 +156,32 @@ def handle_dbuser_deleted(sender, instance, **kwargs):
Signal handler triggered after the deletion of Signal handler triggered after the deletion of
:py:class:`userdbs.models.DatabaseUser` instances. :py:class:`userdbs.models.DatabaseUser` instances.
:param sender: the sender of the signal
:param instance: the DatabaseUser instance
This signal handler starts Celery_ tasks depending on the db_type value of
the database user.
.. blockdiag::
:desctable:
blockdiag {
node_width = 200;
A -> B;
A -> C;
A [ label = "", shape = beginpoint,
description = "this signal handler" ];
B [ label = "delete mysql user", color = "PowderBlue",
description = ":py:func:`delete_mysql_user()
<mysqltasks.tasks.delete_mysql_user>` called with username
from instance.name" ];
C [ label = "delete pgsql user", color = "DodgerBlue",
description = ":py:func:`delete_pgsql_user()
<pgsqltasks.tasks.delete_pgsql_user>` called with username
from instance.name" ];
}
""" """
if instance.db_type == DB_TYPES.mysql: if instance.db_type == DB_TYPES.mysql:
taskresult = TaskResult.objects.create_task_result( taskresult = TaskResult.objects.create_task_result(
@ -126,6 +213,34 @@ def handle_userdb_created(sender, instance, created, **kwargs):
Signal handler triggered after the creation of or updates to Signal handler triggered after the creation of or updates to
:py:class:`userdbs.models.UserDatabase` instances. :py:class:`userdbs.models.UserDatabase` instances.
:param sender: the sender of the signal
:param instance: the UserDatabase instance
:param bool created: whether this signal handler has been called for a
newly created instance
This signal handler starts Celery_ tasks depending on the db_type value of
the database user owning the UserDatabase instance.
.. blockdiag::
:desctable:
blockdiag {
node_width = 200;
A -> B;
A -> C;
A [ label = "", shape = beginpoint,
description = "this signal handler" ];
B [ label = "create mysql database", color = "PowderBlue",
description = ":py:func:`create_mysql_database()
<mysqltasks.tasks.create_mysql_database>` called with database
name and username" ];
C [ label = "create pgsql database", color = "DodgerBlue",
description = ":py:func:`create_pgsql_database()
<pgsqltasks.tasks.create_pgsql_database>` called with database
name and username" ];
}
""" """
if created: if created:
if instance.db_user.db_type == DB_TYPES.mysql: if instance.db_user.db_type == DB_TYPES.mysql:
@ -163,6 +278,32 @@ def handle_userdb_deleted(sender, instance, **kwargs):
Signal handler triggered after the deletion of Signal handler triggered after the deletion of
:py:class:`userdbs.models.UserDatabase` instances. :py:class:`userdbs.models.UserDatabase` instances.
:param sender: the sender of the signal
:param instance: the UserDatabase instance
This signal handler starts Celery_ tasks depending on the db_type value of
the database user owning the UserDatabase instance.
.. blockdiag::
:desctable:
blockdiag {
node_width = 200;
A -> B;
A -> C;
A [ label = "", shape = beginpoint,
description = "this signal handler" ];
B [ label = "delete mysql database", color = "PowderBlue",
description = ":py:func:`delete_mysql_user()
<mysqltasks.tasks.delete_mysql_user>` called with database
name and username" ];
C [ label = "delete pgsql database", color = "DodgerBlue",
description = ":py:func:`delete_pgsql_user()
<pgsqltasks.tasks.delete_pgsql_user>` called with database
name" ];
}
""" """
if instance.db_user.db_type == DB_TYPES.mysql: if instance.db_user.db_type == DB_TYPES.mysql:
taskresult = TaskResult.objects.create_task_result( taskresult = TaskResult.objects.create_task_result(

View file

@ -9,3 +9,4 @@ flake8==2.5.2
mccabe==0.4.0 mccabe==0.4.0
pep8==1.7.0 pep8==1.7.0
pyflakes==1.0.0 pyflakes==1.0.0
sphinxcontrib-blockdiag==1.5.5