diff --git a/docs/changelog.rst b/docs/changelog.rst index 53fa8dd..15f7f1f 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,5 +1,8 @@ Changelog ========= +* :release:`0.0.2 <2014-12-26>` +* :feature:`-` implement tasks for creating and deleting SFTP and mail base directories + * :release:`0.0.1 <2014-12-25>` * :feature:`-` initial setup of django application and celery worker diff --git a/docs/code.rst b/docs/code.rst index 2b273a7..227508a 100644 --- a/docs/code.rst +++ b/docs/code.rst @@ -29,6 +29,12 @@ The project module :py:mod:`gvafile` .. automodule:: gvafile.urls +:py:mod:`gvafile.exceptions` +---------------------------- + +.. automodule:: gvafile.exceptions + + :py:mod:`gvafile.wsgi` ---------------------- diff --git a/docs/conf.py b/docs/conf.py index dc4f85e..7738860 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -14,6 +14,7 @@ import sys import os +import django # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -22,6 +23,10 @@ sys.path.insert(0, os.path.abspath(os.path.join('..', 'gvafile'))) os.environ['GVAFILE_ALLOWED_HOSTS'] = 'localhost' os.environ['GVAFILE_SERVER_EMAIL'] = 'root@localhost' +os.environ['GVAFILE_SFTP_DIRECTORY'] = '/home/www' +os.environ['GVAFILE_MAIL_DIRECTORY'] = '/home/mail' + +django.setup() # -- General configuration ----------------------------------------------------- @@ -57,9 +62,9 @@ copyright = u'2014, Jan Dittberner' # built documents. # # The short X.Y version. -version = '0.0.1' +version = '0.0.2' # The full version, including alpha/beta/rc tags. -release = '0.0.1' +release = '0.0.2' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/gvafile/gvafile/exceptions.py b/gvafile/gvafile/exceptions.py new file mode 100644 index 0000000..06f6cfb --- /dev/null +++ b/gvafile/gvafile/exceptions.py @@ -0,0 +1,12 @@ +""" +This module defines exceptions for gvafile. + +""" +from __future__ import unicode_literals + + +class GVAFileException(Exception): + """ + Generic Exception class for gvafile. + + """ diff --git a/gvafile/gvafile/settings/base.py b/gvafile/gvafile/settings/base.py index 470a9cf..ccdea65 100644 --- a/gvafile/gvafile/settings/base.py +++ b/gvafile/gvafile/settings/base.py @@ -271,6 +271,12 @@ WSGI_APPLICATION = '%s.wsgi.application' % SITE_NAME ########## END WSGI CONFIGURATION +########## GVAFILE CONFIGURATION +GVAFILE_SFTP_DIRECTORY = get_env_setting('GVAFILE_SFTP_DIRECTORY') +GVAFILE_MAIL_DIRECTORY = get_env_setting('GVAFILE_MAIL_DIRECTORY') +########## END GVAFILE CONFIGURATION + + ########## CELERY CONFIGURATION BROKER_URL = get_env_setting('GVAFILE_BROKER_URL') CELERY_RESULT_BACKEND = 'amqp' diff --git a/gvafile/osusers/tasks.py b/gvafile/osusers/tasks.py new file mode 100644 index 0000000..e386a99 --- /dev/null +++ b/gvafile/osusers/tasks.py @@ -0,0 +1,145 @@ +""" +This module defines `Celery`_ tasks to manage file system entities. + +.. _Celery: http://www.celeryproject.org/ + +""" +from __future__ import absolute_import, unicode_literals + +import os +import subprocess + +from django.conf import settings + +from celery import shared_task +from celery.utils.log import get_task_logger + +from gvafile.exceptions import GVAFileException + + +_logger = get_task_logger(__name__) + +SUDO_CMD = '/usr/bin/sudo' +INSTALL_CMD = '/usr/bin/install' +SETFACL_CMD = '/usr/bin/setfacl' +RM_CMD = '/bin/rm' + + +def _build_sftp_directory_name(username): + """ + Constructs the SFTP directory name for a given username. + + """ + return os.path.join(settings.GVAFILE_SFTP_DIRECTORY, username) + + +def _build_mail_directory_name(username): + """ + Constructs the mailbox directory name for a given username. + + """ + return os.path.join(settings.GVAFILE_MAIL_DIRECTORY, username) + + +@shared_task +def setup_file_sftp_userdir(username): + """ + This task creates the home directory for an SFTP user if it does not exist + yet. + + :param str username: the user name + :raises Exception: if the SFTP directory of the user cannot be created + :return: the created directory name + :rtype: str + + """ + sftp_directory = _build_sftp_directory_name(username) + try: + subprocess.check_output([ + SUDO_CMD, INSTALL_CMD, '-o', username, '-g', username, + '-m', '0750', '-d', sftp_directory], stderr=subprocess.STDOUT) + subprocess.check_output([ + SUDO_CMD, SETFACL_CMD, '-m', 'www-data:--x', + sftp_directory], stderr=subprocess.STDOUT) + except subprocess.CalledProcessError: + _logger.exception( + 'could not create SFTP directory for user %s', username) + raise GVAFileException( + "could not create SFTP directory for user %s" % username) + return sftp_directory + + +@shared_task +def delete_file_sftp_userdir(username): + """ + This task recursively deletes the home directory of an SFTP user if it + does not exist yet. + + :param str username: the user name + :raises Exception: if the SFTP directory of the user cannot be removed + :return: the removed directory name + :rtype: str + + """ + sftp_directory = _build_sftp_directory_name(username) + try: + subprocess.check_output([ + SUDO_CMD, RM_CMD, '-r', '-f', sftp_directory], + stderr=subprocess.STDOUT) + except subprocess.CalledProcessError: + _logger.exception( + 'could not remove SFTP directory for user %s', username) + raise GVAFileException( + "could not remove SFTP directory for user %s" % username) + return sftp_directory + + +@shared_task +def setup_file_mail_userdir(username): + """ + This task creates the mail base directory for a user if it does not exist + yet. + + :param str username: the user name + :raises Exception: if the mail base directory for the user cannot be + created + :return: the created directory name + :rtype: str + + """ + mail_directory = _build_mail_directory_name(username) + try: + subprocess.check_output([ + SUDO_CMD, INSTALL_CMD, '-o', username, '-g', username, + '-m', '0750', '-d', mail_directory], stderr=subprocess.STDOUT) + except subprocess.CalledProcessError: + _logger.exception( + 'could not create mail base directory for user %s', username) + raise GVAFileException( + "could not create mail base directory for user %s" % username) + return mail_directory + + +@shared_task +def delete_file_mail_userdir(username): + """ + This task recursively deletes the mail base directory for a user if it + does not exist yet. + + :param str username: the user name + :raises Exception: if the mail base directory of the user cannot be removed + :return: the removed directory name + :rtype: str + + """ + mail_directory = _build_mail_directory_name(username) + try: + subprocess.check_output([ + SUDO_CMD, RM_CMD, '-r', '-f', mail_directory], + stderr=subprocess.STDOUT) + except subprocess.CalledProcessError: + _logger.exception( + 'could not remove mail base directory of user %s', username) + raise GVAFileException( + "could not remove mail base directory of user %s" % username) + return mail_directory