Merge branch 'release/0.5.0' into production

* release/0.5.0:
  update docs version, add release to changelog
  add missing - to install parameter
  add return value as documented
  add logging for set_file_ssh_authorized_keys
  add new task set_file_ssh_authorized_keys
  improved logging in fileservertasks.tasks
This commit is contained in:
Jan Dittberner 2015-01-29 22:59:10 +01:00
commit 420d34dfea
6 changed files with 146 additions and 69 deletions

View file

@ -1,6 +1,12 @@
Changelog Changelog
========= =========
* :release:`0.5.0 <2015-01-29>`
* :feature:`-` add new task set_file_ssh_authorized_keys to add SSH keys for
users
* :support:`-` improved logging in fileservertasks.tasks, got rid of
GVAFileException
* :release:`0.4.0 <2015-01-26>` * :release:`0.4.0 <2015-01-26>`
* :feature:`-` implement new tasks create_file_website_hierarchy and * :feature:`-` implement new tasks create_file_website_hierarchy and
delete_file_website_hierarchy delete_file_website_hierarchy

View file

@ -20,12 +20,6 @@ The project module :py:mod:`gvafile`
:members: :members:
:py:mod:`exceptions <gvafile.exceptions>`
-----------------------------------------
.. automodule:: gvafile.exceptions
:py:mod:`settings <gvafile.settings>` :py:mod:`settings <gvafile.settings>`
------------------------------------- -------------------------------------
@ -33,8 +27,8 @@ The project module :py:mod:`gvafile`
:members: :members:
:py:mod:`fileservertasks` app :py:mod:`fileservertasks` module
============================= ================================
.. automodule:: fileservertasks .. automodule:: fileservertasks

View file

@ -59,9 +59,9 @@ copyright = u'2014, 2015 Jan Dittberner'
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
version = '0.4' version = '0.5'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = '0.4.0' release = '0.5.0'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.

View file

@ -8,16 +8,14 @@ from __future__ import absolute_import, unicode_literals
import os import os
import subprocess import subprocess
from tempfile import mkstemp
from gvafile import settings from gvafile import settings
from celery import shared_task from celery import shared_task
from celery.utils.log import get_task_logger from celery.utils.log import get_task_logger
from gvafile.exceptions import GVAFileException _LOGGER = get_task_logger(__name__)
_logger = get_task_logger(__name__)
SUDO_CMD = '/usr/bin/sudo' SUDO_CMD = '/usr/bin/sudo'
INSTALL_CMD = '/usr/bin/install' INSTALL_CMD = '/usr/bin/install'
@ -25,6 +23,34 @@ SETFACL_CMD = '/usr/bin/setfacl'
RM_CMD = '/bin/rm' RM_CMD = '/bin/rm'
def log_and_raise(exception, message, *args):
"""
Log and raise a :py:class:`subprocess.CalledProcessError`.
:param exception: exception
:param str message: log message
:param args: arguments to fill placeholders in message
:raises Exception: raises an exception with the formatted message
"""
logargs = list(args) + [exception.returncode, exception.output]
_LOGGER.error(message + "\nreturncode: %d\noutput:\n%s", *logargs)
raise Exception(message % args)
def _build_authorized_keys_path(username):
"""
Constructs the file path for the authorized_keys file for a given username.
:param str username: the user name
:return: the file name
:rtype: str
"""
return os.path.join(
settings.GVAFILE_SFTP_AUTHKEYS_DIRECTORY, username, 'keys')
def _build_sftp_directory_name(username): def _build_sftp_directory_name(username):
""" """
Constructs the SFTP directory name for a given username. Constructs the SFTP directory name for a given username.
@ -61,11 +87,11 @@ def setup_file_sftp_userdir(username):
subprocess.check_output([ subprocess.check_output([
SUDO_CMD, SETFACL_CMD, '-m', 'www-data:--x', SUDO_CMD, SETFACL_CMD, '-m', 'www-data:--x',
sftp_directory], stderr=subprocess.STDOUT) sftp_directory], stderr=subprocess.STDOUT)
except subprocess.CalledProcessError: except subprocess.CalledProcessError as cpe:
_logger.exception( log_and_raise(
'could not create SFTP directory for user %s', username) cpe, 'cold not create SFTP directory for user %s', username)
raise GVAFileException( _LOGGER.info(
"could not create SFTP directory for user %s" % username) 'created sftp directory %s for user %s', sftp_directory, username)
return sftp_directory return sftp_directory
@ -86,11 +112,11 @@ def delete_file_sftp_userdir(username):
subprocess.check_output([ subprocess.check_output([
SUDO_CMD, RM_CMD, '-r', '-f', sftp_directory], SUDO_CMD, RM_CMD, '-r', '-f', sftp_directory],
stderr=subprocess.STDOUT) stderr=subprocess.STDOUT)
except subprocess.CalledProcessError: except subprocess.CalledProcessError as cpe:
_logger.exception( log_and_raise(
'could not remove SFTP directory for user %s', username) cpe, 'could not remove SFTP directory for user %s', username)
raise GVAFileException( _LOGGER.info(
"could not remove SFTP directory for user %s" % username) "deleted sftp directory %s of user %s", sftp_directory, username)
return sftp_directory return sftp_directory
@ -112,11 +138,11 @@ def setup_file_mail_userdir(username):
subprocess.check_output([ subprocess.check_output([
SUDO_CMD, INSTALL_CMD, '-o', username, '-g', username, SUDO_CMD, INSTALL_CMD, '-o', username, '-g', username,
'-m', '0500', '-d', mail_directory], stderr=subprocess.STDOUT) '-m', '0500', '-d', mail_directory], stderr=subprocess.STDOUT)
except subprocess.CalledProcessError: except subprocess.CalledProcessError as cpe:
_logger.exception( log_and_raise(
'could not create mail base directory for user %s', username) cpe, 'could not create mail base directory for user %s', username)
raise GVAFileException( _LOGGER.info(
"could not create mail base directory for user %s" % username) 'created mail directory %s for user %s', mail_directory, username)
return mail_directory return mail_directory
@ -137,11 +163,11 @@ def delete_file_mail_userdir(username):
subprocess.check_output([ subprocess.check_output([
SUDO_CMD, RM_CMD, '-r', '-f', mail_directory], SUDO_CMD, RM_CMD, '-r', '-f', mail_directory],
stderr=subprocess.STDOUT) stderr=subprocess.STDOUT)
except subprocess.CalledProcessError: except subprocess.CalledProcessError as cpe:
_logger.exception( log_and_raise(
'could not remove mail base directory of user %s', username) cpe, 'could not remove mail base directory of user %s', username)
raise GVAFileException( _LOGGER.info(
"could not remove mail base directory of user %s" % username) 'deleted mail directory %s of user %s', mail_directory, username)
return mail_directory return mail_directory
@ -153,7 +179,7 @@ def create_file_mailbox(username, mailboxname):
:param str username: the user name :param str username: the user name
:param str mailboxname: the mailbox name :param str mailboxname: the mailbox name
:raises GVAFileException: if the mailbox directory cannot be created :raises Exception: if the mailbox directory cannot be created
:return: the created mailbox directory name :return: the created mailbox directory name
:rtype: str :rtype: str
@ -164,12 +190,13 @@ def create_file_mailbox(username, mailboxname):
subprocess.check_output([ subprocess.check_output([
SUDO_CMD, INSTALL_CMD, '-o', username, '-g', username, SUDO_CMD, INSTALL_CMD, '-o', username, '-g', username,
'-m', '0700', '-d', mailbox_directory], stderr=subprocess.STDOUT) '-m', '0700', '-d', mailbox_directory], stderr=subprocess.STDOUT)
except subprocess.CalledProcessError: except subprocess.CalledProcessError as cpe:
_logger.exception( log_and_raise(
'could not create mailbox %s for user %s', mailboxname, username) cpe, 'could not create mailbox %s for user %s', mailboxname,
raise GVAFileException( username)
"could not create mailbox %s for user %s" % (mailboxname, username) _LOGGER.info(
) 'created mailbox directory %s for user %s', mailbox_directory,
username)
return mailbox_directory return mailbox_directory
@ -180,7 +207,7 @@ def delete_file_mailbox(username, mailboxname):
:param str username: the user name :param str username: the user name
:param str mailboxname: the mailbox name :param str mailboxname: the mailbox name
:raises GVAFileException: if the mailbox directory cannot be deleted :raises Exception: if the mailbox directory cannot be deleted
:return: the deleted mailbox directory name :return: the deleted mailbox directory name
:rtype: str :rtype: str
@ -191,11 +218,12 @@ def delete_file_mailbox(username, mailboxname):
subprocess.check_output([ subprocess.check_output([
SUDO_CMD, RM_CMD, '-r', '-f', mailbox_directory], SUDO_CMD, RM_CMD, '-r', '-f', mailbox_directory],
stderr=subprocess.STDOUT) stderr=subprocess.STDOUT)
except subprocess.CalledProcessError: except subprocess.CalledProcessError as cpe:
_logger.exception( log_and_raise(
'could not remove mailbox %s of user %s', mailboxname, username) cpe, 'could not remove mailbox %s of user %s', mailboxname,
raise GVAFileException( username)
"could not remove mailbox %s of user %s" % (mailboxname, username)) _LOGGER.info(
'deleted mailbox directory %s of user %s', mailbox_directory, username)
return mailbox_directory return mailbox_directory
@ -206,6 +234,8 @@ def create_file_website_hierarchy(username, sitename):
:param str username: the user name :param str username: the user name
:param str sitename: name of the website :param str sitename: name of the website
:raises Exception: if the website directory hierarchy directory cannot be
created
:return: the directory name :return: the directory name
:rtype: str :rtype: str
@ -233,13 +263,14 @@ def create_file_website_hierarchy(username, sitename):
subprocess.check_output([ subprocess.check_output([
SUDO_CMD, INSTALL_CMD, '-o', username, '-g', username, SUDO_CMD, INSTALL_CMD, '-o', username, '-g', username,
'-m', '0750', '-d', tmpdir], stderr=subprocess.STDOUT) '-m', '0750', '-d', tmpdir], stderr=subprocess.STDOUT)
except subprocess.CalledProcessError: except subprocess.CalledProcessError as cpe:
_logger.exception( log_and_raise(
cpe,
("could not setup website file hierarchy for user %s's " ("could not setup website file hierarchy for user %s's "
"website %s"), username, sitename) "website %s"), username, sitename)
raise GVAFileException( _LOGGER.info(
("could not setup website file hierarchy for user %s's " 'created website directory %s for user %s', website_directory,
"website %s") % (username, sitename)) username)
return website_directory return website_directory
@ -250,6 +281,8 @@ def delete_file_website_hierarchy(username, sitename):
:param str username: the user name :param str username: the user name
:param str sitename: name of the website :param str sitename: name of the website
:raises Exception: if the website directory hierarchy directory cannot be
deleted
:return: the directory name :return: the directory name
:rtype: str :rtype: str
@ -260,11 +293,65 @@ def delete_file_website_hierarchy(username, sitename):
subprocess.check_output([ subprocess.check_output([
SUDO_CMD, RM_CMD, '-r', '-f', website_directory], SUDO_CMD, RM_CMD, '-r', '-f', website_directory],
stderr=subprocess.STDOUT) stderr=subprocess.STDOUT)
except subprocess.CalledProcessError: except subprocess.CalledProcessError as cpe:
_logger.exception( log_and_raise(
cpe,
("could not delete the website file hierarchy of user %s's " ("could not delete the website file hierarchy of user %s's "
"website %s"), username, sitename) "website %s"), username, sitename)
raise GVAFileException( _LOGGER.info(
("could not delete the website file hierarchy of user %s's " 'deleted website directory %s of user %s', website_directory, username)
"website %s") % (username, sitename))
return website_directory return website_directory
@shared_task
def set_file_ssh_authorized_keys(username, ssh_keys):
"""
This task sets the authorized keys for ssh logins.
:param str username: the user name
:param list ssh_key: an ssh_key
:raises Exception: if the update of the creation or update of ssh
authorized_keys failed
:return: the name of the authorized_keys file
:rtype: str
"""
ssh_authorized_keys_file = _build_authorized_keys_path(username)
if ssh_keys:
try:
authkeystemp, filename = mkstemp()
conffile = os.fdopen(authkeystemp, 'w')
conffile.write("\n".join(ssh_keys))
finally:
if conffile:
conffile.close()
try:
subprocess.check_output([
SUDO_CMD, INSTALL_CMD, '-o', username, '-g', username,
'-m', '0500', '-d', os.path.dirname(ssh_authorized_keys_file)],
stderr=subprocess.STDOUT)
subprocess.check_output([
SUDO_CMD, INSTALL_CMD, '-o', username, '-g', username,
'-m', '0400', filename, ssh_authorized_keys_file],
stderr=subprocess.STDOUT)
subprocess.check_output([
SUDO_CMD, RM_CMD, filename], stderr=subprocess.STDOUT)
_LOGGER.info(
'set %d authorized_keys for user %s', len(ssh_keys), username)
except subprocess.CalledProcessError as cpe:
log_and_raise(
cpe, 'could not write authorized_keys file for user %s',
username)
else:
try:
subprocess.check_output([
SUDO_CMD, RM_CMD, '-rf',
os.path.dirname(ssh_authorized_keys_file)],
stderr=subprocess.STDOUT)
_LOGGER.info(
'deleted authorized_keys of user %s', username)
except subprocess.CalledProcessError as cpe:
log_and_raise(
cpe, 'could not remove the authorized_keys file of user %s',
username)
return ssh_authorized_keys_file

View file

@ -1,12 +0,0 @@
"""
This module defines exceptions for gvafile.
"""
from __future__ import unicode_literals
class GVAFileException(Exception):
"""
Generic Exception class for gvafile.
"""

View file

@ -42,4 +42,6 @@ BROKER_URL = get_env_setting('GVAFILE_BROKER_URL')
########## GVAFILE CONFIGURATION ########## GVAFILE CONFIGURATION
GVAFILE_SFTP_DIRECTORY = get_env_setting('GVAFILE_SFTP_DIRECTORY') GVAFILE_SFTP_DIRECTORY = get_env_setting('GVAFILE_SFTP_DIRECTORY')
GVAFILE_MAIL_DIRECTORY = get_env_setting('GVAFILE_MAIL_DIRECTORY') GVAFILE_MAIL_DIRECTORY = get_env_setting('GVAFILE_MAIL_DIRECTORY')
GVAFILE_SFTP_AUTHKEYS_DIRECTORY = get_env_setting(
'GVAFILE_SFTP_AUTHKEYS_DIRECTORY')
########## END GVAFILE CONFIGURATION ########## END GVAFILE CONFIGURATION