""" This module defines Celery_ tasks to manage website configurations. """ import os import subprocess from tempfile import mkstemp from jinja2 import Environment, PackageLoader from celery import shared_task from celery.utils.log import get_task_logger from gvaweb import settings _LOGGER = get_task_logger(__name__) SUDO_CMD = '/usr/bin/sudo' RM_CMD = '/bin/rm' LN_CMD = '/bin/ln' SERVICE_CMD = '/bin/systemctl' INSTALL_CMD = '/usr/bin/install' JINJAENV = Environment(loader=PackageLoader('gvaweb.webtasks', 'templates')) def _jinja_parentdomain(domain): return '.'.join(domain.split('.')[1:]) JINJAENV.filters['parentdomain'] = _jinja_parentdomain def log_and_raise(exception, message, *args): logargs = list(args) + [exception.returncode, exception.output] _LOGGER.error(message + "\nreturncode: %d\noutput:\n%s", *logargs) raise Exception(message % args) def log_without_raise(exception, message, *args): logargs = list(args) + [exception.returncode, exception.output] _LOGGER.error(message + "\nreturncode: %d\noutput:\n%s", *logargs) def _build_vhost_config_path(sitename): return os.path.join(settings.GVAWEB_NGINX_SITES_AVAILABLE, sitename) def _build_enabled_vhost_path(sitename): return os.path.join(settings.GVAWEB_NGINX_SITES_ENABLED, sitename) def _build_php_fpm_pool_file(username): return os.path.join(settings.GVAWEB_PHPFPM_POOL, "{username}.conf".format( username=username)) def _build_document_root_path(sitename, username): return os.path.join( settings.GVAWEB_WWWUSER_MOUNT, username, sitename, 'html') def _get_template(templatename): return JINJAENV.get_template(templatename) @shared_task def create_web_vhost_config(username, sitename, wildcard): """ This task creates a virtual host configuration on an nginx web server. :param str username: user who owns the site :param str sitename: site name :param boolean wildcard: designates whether this is website has a wildcard subdomain :return: :py:const:`True` if the creation finished successfully :rtype: boolean """ conftmpl = _get_template('vhost.nginx') confdata = conftmpl.render(domain=sitename, wildcard=wildcard) conffile = None try: nginxtemp, filename = mkstemp() conffile = os.fdopen(nginxtemp, 'w') conffile.write(confdata.encode('utf8')) finally: if conffile: conffile.close() try: subprocess.check_output([ SUDO_CMD, INSTALL_CMD, '-o', 'root', '-g', 'root', '-m', '0640', filename, _build_vhost_config_path(sitename)], stderr=subprocess.STDOUT) subprocess.check_output([ SUDO_CMD, RM_CMD, filename], stderr=subprocess.STDOUT) except subprocess.CalledProcessError as cpe: log_and_raise( cpe, 'could not setup site configuration for %s', sitename) return True @shared_task def disable_web_vhost(sitename): """ This task disables a virtual host configuration on an nginx web server. :param str sitename: site name :return: :py:const:`True` if the virtual host has been disabled :rtype: boolean """ try: subprocess.check_output([ SUDO_CMD, RM_CMD, "-f", _build_enabled_vhost_path(sitename)], stderr=subprocess.STDOUT) subprocess.check_output([ SUDO_CMD, SERVICE_CMD, 'reload', 'nginx'], stderr=subprocess.STDOUT) except subprocess.CalledProcessError as cpe: log_and_raise( cpe, 'could not disable site configuration for %s', sitename) return True @shared_task def enable_web_vhost(sitename): """ This task enables an existing virtual host configuration on an nginx web server. :param str sitename: site name :return: :py:const:`True` if the virtual host has been enabled :rtype: boolean """ try: subprocess.check_output([ SUDO_CMD, LN_CMD, '-s', '-f', _build_vhost_config_path(sitename), _build_enabled_vhost_path(sitename)], stderr=subprocess.STDOUT) subprocess.check_output([ SUDO_CMD, SERVICE_CMD, 'restart', 'nginx'], stderr=subprocess.STDOUT) except subprocess.CalledProcessError as cpe: log_and_raise( cpe, 'could not enable site configuration for %s', sitename) return True @shared_task def delete_web_vhost_config(sitename): """ This task removes a virtual host configuration on an nginx web server. :param str sitename: site name :return: :py:const:`True` if the configuration has been deleted :rtype: boolean """ try: subprocess.check_output([ SUDO_CMD, RM_CMD, "-f", _build_vhost_config_path(sitename)], stderr=subprocess.STDOUT) except subprocess.CalledProcessError as cpe: log_and_raise( cpe, 'could not delete site configuration for %s', sitename) return True @shared_task def create_web_php_fpm_pool_config(username): """ This task creates a PHP FPM pool configuration. :param str username: user name :return: :py:const:`True` if the creation finished successfully :rtype: boolean """ # TODO: implement PHP FPM docker management return True @shared_task def delete_web_php_fpm_pool_config(username): """ This task deletes a PHP FPM pool configuration. :param str username: user name :return: :py:const:`True` if the pool has been deleted :rtype: boolean """ try: subprocess.check_output([ SUDO_CMD, RM_CMD, "-f", _build_php_fpm_pool_file(username)], stderr=subprocess.STDOUT) except subprocess.CalledProcessError as cpe: log_without_raise( cpe, 'could not delete PHP FPM configuration for %s', username) return True