Jan Dittberner
26aae0173d
This change moves the fileservertasks module to the top level to allow keeping the same task names when running in a Python 3 environment.
671 lines
24 KiB
Python
671 lines
24 KiB
Python
"""
|
|
This module defines `Celery`_ tasks to manage file system entities.
|
|
|
|
.. _Celery: http://www.celeryproject.org/
|
|
|
|
"""
|
|
from __future__ import absolute_import, unicode_literals
|
|
|
|
from copy import deepcopy
|
|
import os
|
|
import subprocess
|
|
from tempfile import mkstemp
|
|
|
|
from fileservertasks import settings
|
|
|
|
from celery import shared_task
|
|
from celery.utils.log import get_task_logger
|
|
|
|
_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 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):
|
|
"""
|
|
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, *args, **kwargs):
|
|
"""
|
|
This task creates the home directory for an SFTP user if it does not exist
|
|
yet.
|
|
|
|
:param str username: the username
|
|
:raises Exception: if the SFTP directory of the user cannot be created
|
|
:return: a dictionary with the key :py:const:`username` set to the
|
|
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.
|
|
|
|
"""
|
|
sftp_directory = _build_sftp_directory_name(username)
|
|
try:
|
|
subprocess.check_output([
|
|
SUDO_CMD, INSTALL_CMD, '-o', 'root', '-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 as cpe:
|
|
log_and_raise(
|
|
cpe, 'could not create SFTP directory %s for user %s',
|
|
sftp_directory, username)
|
|
_LOGGER.info(
|
|
'created sftp directory %s for user %s', sftp_directory, username)
|
|
return {'username': username, 'sftp_directory': sftp_directory}
|
|
|
|
|
|
@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
|
|
|
|
"""
|
|
username = previous_result['username']
|
|
retval = deepcopy(previous_result)
|
|
retval.update(setup_file_sftp_userdir(username))
|
|
return retval
|
|
|
|
|
|
@shared_task
|
|
def delete_file_sftp_userdir(username, *args, **kwargs):
|
|
"""
|
|
This task recursively deletes the home directory of an SFTP user if it
|
|
exists.
|
|
|
|
:param str username: the username
|
|
:raises Exception: if the SFTP directory of the user cannot be removed
|
|
:return: a dictionary with the key :py:const:`username` set to the username
|
|
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.
|
|
|
|
"""
|
|
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 as cpe:
|
|
log_and_raise(
|
|
cpe, 'could not remove SFTP directory for user %s', username)
|
|
_LOGGER.info(
|
|
"deleted sftp directory %s of user %s", sftp_directory, username)
|
|
return {'username': username, 'sftp_directory': sftp_directory}
|
|
|
|
|
|
@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
|
|
|
|
"""
|
|
username = previous_result['username']
|
|
retval = deepcopy(previous_result)
|
|
retval.update(delete_file_sftp_userdir(username))
|
|
return retval
|
|
|
|
|
|
@shared_task
|
|
def setup_file_mail_userdir(username, *args, **kwargs):
|
|
"""
|
|
This task creates the mail base directory for a user if it does not exist
|
|
yet.
|
|
|
|
:param str username: the username
|
|
:raises Exception: if the mail base directory for the user cannot be
|
|
created
|
|
: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 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.
|
|
|
|
"""
|
|
mail_directory = _build_mail_directory_name(username)
|
|
try:
|
|
subprocess.check_output([
|
|
SUDO_CMD, INSTALL_CMD, '-o', username, '-g', username,
|
|
'-m', '0500', '-d', mail_directory], stderr=subprocess.STDOUT)
|
|
except subprocess.CalledProcessError as cpe:
|
|
log_and_raise(
|
|
cpe, 'could not create mail base directory for user %s', username)
|
|
_LOGGER.info(
|
|
'created mail directory %s for user %s', mail_directory, username)
|
|
return {'username': username, 'mail_directory': mail_directory}
|
|
|
|
|
|
@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
|
|
|
|
"""
|
|
username = previous_result['username']
|
|
retval = deepcopy(previous_result)
|
|
retval.update(setup_file_mail_userdir(username))
|
|
return retval
|
|
|
|
|
|
@shared_task
|
|
def delete_file_mail_userdir(username, *args, **kwargs):
|
|
"""
|
|
This task recursively deletes the mail base directory for a user if it
|
|
does not exist yet.
|
|
|
|
:param str username: the username
|
|
:raises Exception: if the mail base directory of the user cannot be deleted
|
|
: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.
|
|
|
|
"""
|
|
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 as cpe:
|
|
log_and_raise(
|
|
cpe, 'could not remove mail base directory of user %s', username)
|
|
_LOGGER.info(
|
|
'deleted mail directory %s of user %s', mail_directory, username)
|
|
return {'username': username, 'mail_directory': mail_directory}
|
|
|
|
@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
|
|
|
|
"""
|
|
username = previous_result['username']
|
|
retval = deepcopy(previous_result)
|
|
retval.update(delete_file_mail_userdir(username))
|
|
return retval
|
|
|
|
|
|
@shared_task
|
|
def create_file_mailbox(username, mailboxname, *args, **kwargs):
|
|
"""
|
|
This task creates a new mailbox directory for the given user and mailbox
|
|
name.
|
|
|
|
:param str username: the username
|
|
:param str mailboxname: the mailbox name
|
|
:raises Exception: if the mailbox directory cannot be created
|
|
:return: a dictionary with the keys :py:const:`username` and
|
|
: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.
|
|
|
|
"""
|
|
mailbox_directory = os.path.join(
|
|
_build_mail_directory_name(username), mailboxname)
|
|
try:
|
|
subprocess.check_output([
|
|
SUDO_CMD, INSTALL_CMD, '-o', username, '-g', username,
|
|
'-m', '0700', '-d', mailbox_directory], stderr=subprocess.STDOUT)
|
|
except subprocess.CalledProcessError as cpe:
|
|
log_and_raise(
|
|
cpe, 'could not create mailbox %s for user %s', mailboxname,
|
|
username)
|
|
_LOGGER.info(
|
|
'created mailbox directory %s for user %s', mailbox_directory,
|
|
username)
|
|
return {
|
|
'username': username, 'mailboxname': mailboxname,
|
|
'mailbox_directory': mailbox_directory
|
|
}
|
|
|
|
|
|
@shared_task
|
|
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
|
|
|
|
"""
|
|
username = previous_result['username']
|
|
mailboxname = previous_result['mailboxname']
|
|
retval = deepcopy(previous_result)
|
|
retval.update(create_file_mailbox(username, mailboxname))
|
|
return retval
|
|
|
|
|
|
@shared_task
|
|
def delete_file_mailbox(username, mailboxname, *args, **kwargs):
|
|
"""
|
|
This task deletes the given mailbox of the given user.
|
|
|
|
:param str username: the username
|
|
:param str mailboxname: the mailbox name
|
|
:raises Exception: if the mailbox directory cannot be deleted
|
|
:return: a dictionary with the keys :py:const:`username` and
|
|
: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.
|
|
|
|
"""
|
|
mailbox_directory = os.path.join(
|
|
_build_mail_directory_name(username), mailboxname)
|
|
try:
|
|
subprocess.check_output([
|
|
SUDO_CMD, RM_CMD, '-r', '-f', mailbox_directory],
|
|
stderr=subprocess.STDOUT)
|
|
except subprocess.CalledProcessError as cpe:
|
|
log_and_raise(
|
|
cpe, 'could not remove mailbox %s of user %s', mailboxname,
|
|
username)
|
|
_LOGGER.info(
|
|
'deleted mailbox directory %s of user %s', mailbox_directory, username)
|
|
return {
|
|
'username': username, 'mailboxname': mailboxname,
|
|
'mailbox_directory': mailbox_directory
|
|
}
|
|
|
|
@shared_task
|
|
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
|
|
|
|
"""
|
|
username = previous_result['username']
|
|
mailboxname = previous_result['mailboxname']
|
|
retval = deepcopy(previous_result)
|
|
retval.update(delete_file_mailbox(username, mailboxname))
|
|
return retval
|
|
|
|
|
|
@shared_task
|
|
def create_file_website_hierarchy(username, sitename, *args, **kwargs):
|
|
"""
|
|
This task creates the directory hierarchy for a website.
|
|
|
|
:param str username: the username
|
|
:param str sitename: the sitename
|
|
:raises Exception: if the website directory hierarchy directory cannot be
|
|
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
|
|
|
|
"""
|
|
website_directory = os.path.join(
|
|
_build_sftp_directory_name(username), sitename)
|
|
try:
|
|
subprocess.check_output([
|
|
SUDO_CMD, INSTALL_CMD, '-o', 'root', '-g', username,
|
|
'-m', '0750', '-d', website_directory], stderr=subprocess.STDOUT)
|
|
subprocess.check_output([
|
|
SUDO_CMD, SETFACL_CMD, '-m', 'www-data:--x',
|
|
website_directory], stderr=subprocess.STDOUT)
|
|
htmldir = os.path.join(website_directory, 'html')
|
|
subprocess.check_output([
|
|
SUDO_CMD, INSTALL_CMD, '-o', username, '-g', username,
|
|
'-m', '0750', '-d', htmldir], stderr=subprocess.STDOUT)
|
|
subprocess.check_output([
|
|
SUDO_CMD, SETFACL_CMD, '-m', 'www-data:r-x',
|
|
htmldir], stderr=subprocess.STDOUT)
|
|
subprocess.check_output([
|
|
SUDO_CMD, SETFACL_CMD, '-d', '-m', 'www-data:r-X',
|
|
htmldir], stderr=subprocess.STDOUT)
|
|
tmpdir = os.path.join(website_directory, 'tmp')
|
|
subprocess.check_output([
|
|
SUDO_CMD, INSTALL_CMD, '-o', username, '-g', username,
|
|
'-m', '0750', '-d', tmpdir], stderr=subprocess.STDOUT)
|
|
except subprocess.CalledProcessError as cpe:
|
|
log_and_raise(
|
|
cpe,
|
|
("could not setup website file hierarchy for user %s's "
|
|
"website %s"), username, sitename)
|
|
_LOGGER.info(
|
|
'created website directory %s for user %s', website_directory,
|
|
username)
|
|
return {
|
|
'username': username, 'sitename': sitename,
|
|
'website_directory': website_directory,
|
|
}
|
|
|
|
|
|
@shared_task
|
|
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
|
|
|
|
"""
|
|
username = previous_result['username']
|
|
sitename = previous_result['sitename']
|
|
retval = deepcopy(previous_result)
|
|
retval.update(create_file_website_hierarchy(username, sitename))
|
|
return retval
|
|
|
|
|
|
@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
|
|
|
|
"""
|
|
website_directory = os.path.join(
|
|
_build_sftp_directory_name(username), sitename)
|
|
try:
|
|
subprocess.check_output([
|
|
SUDO_CMD, RM_CMD, '-r', '-f', website_directory],
|
|
stderr=subprocess.STDOUT)
|
|
except subprocess.CalledProcessError as cpe:
|
|
log_and_raise(
|
|
cpe,
|
|
("could not delete the website file hierarchy of user %s's "
|
|
"website %s"), username, sitename)
|
|
_LOGGER.info(
|
|
'deleted website directory %s of user %s', website_directory, username)
|
|
return {
|
|
'username': username, 'sitename': sitename,
|
|
'website_directory': website_directory,
|
|
}
|
|
|
|
|
|
@shared_task
|
|
def delete_file_website_hierarchy_chained(previous_result, *args, **kwargs):
|
|
"""
|
|
This task deletes the website hierarchy recursively.
|
|
|
|
: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
|
|
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
|
|
|
|
"""
|
|
username = previous_result['username']
|
|
sitename = previous_result['sitename']
|
|
retval = deepcopy(previous_result)
|
|
retval.update(delete_file_website_hierarchy(username, sitename))
|
|
return retval
|
|
|
|
|
|
@shared_task
|
|
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
|
|
|
|
"""
|
|
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 {
|
|
'username': username, 'ssh_keys': ssh_keys,
|
|
'ssh_authorized_keys': ssh_authorized_keys_file,
|
|
}
|
|
|
|
|
|
@shared_task
|
|
def set_file_ssh_authorized_keys_chained(previous_result, *args, **kwargs):
|
|
"""
|
|
This task sets the authorized keys for ssh logins.
|
|
|
|
: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:`ssh_keys` key
|
|
:raises Exception: if the update of the creation or update of ssh
|
|
authorized_keys failed
|
|
:return: a copy of the :py:obj:`previous_result` dictionary with a new
|
|
:py:const:`ssh_authorized_keys` set to the path of the SSH
|
|
authorized_keys file
|
|
:rtype: dict
|
|
|
|
"""
|
|
username = previous_result['username']
|
|
ssh_keys = previous_result['ssh_keys']
|
|
retval = deepcopy(previous_result)
|
|
retval.update(set_file_ssh_authorized_keys(username, ssh_keys))
|
|
return retval
|