Merge branch 'release/0.1.0' into production
* release/0.1.0: add release version in changelog, update conf.py unify exception handling, fix nginx template fix listen directive wheezy's /bin/ln does not support '-r' parameter implement Jinja filter to calculate the parent domain of a domain remove pool error_log directive which is only allowed globally don't try to close tempfiles twice first tasks implementation, added nginx and FPM templates add wildcard support to create_web_vhost_config task
This commit is contained in:
commit
1494c2ce8a
6 changed files with 168 additions and 3 deletions
|
@ -1,4 +1,9 @@
|
||||||
Changelog
|
Changelog
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
* :release:`0.1.0 <2015-01-27>`
|
||||||
|
* :feature:`-` add tasks to setup and delete per user PHP5 FPM pool
|
||||||
|
configurations
|
||||||
|
* :feature:`-` add tasks to setup, enable, disable and delete nginx virtual
|
||||||
|
host configurations
|
||||||
* :support:`-` initial project setup
|
* :support:`-` initial project setup
|
||||||
|
|
|
@ -60,9 +60,9 @@ copyright = u'2015, Jan Dittberner'
|
||||||
# built documents.
|
# built documents.
|
||||||
#
|
#
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '0.0'
|
version = '0.1'
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = '0.0.0'
|
release = '0.1.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.
|
||||||
|
|
|
@ -5,6 +5,10 @@ This module defines Celery_ tasks to manage website configurations.
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import subprocess
|
||||||
|
from tempfile import mkstemp
|
||||||
|
|
||||||
|
from jinja2 import Environment, PackageLoader
|
||||||
|
|
||||||
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
|
||||||
|
@ -20,6 +24,21 @@ LN_CMD = '/bin/ln'
|
||||||
SERVICE_CMD = '/usr/sbin/service'
|
SERVICE_CMD = '/usr/sbin/service'
|
||||||
INSTALL_CMD = '/usr/bin/install'
|
INSTALL_CMD = '/usr/bin/install'
|
||||||
|
|
||||||
|
JINJAENV = Environment(loader=PackageLoader('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 _build_vhost_config_path(sitename):
|
def _build_vhost_config_path(sitename):
|
||||||
return os.path.join(settings.GVAWEB_NGINX_SITES_AVAILABLE, sitename)
|
return os.path.join(settings.GVAWEB_NGINX_SITES_AVAILABLE, sitename)
|
||||||
|
@ -39,18 +58,47 @@ def _build_document_root_path(sitename, username):
|
||||||
settings.GVAWEB_WWWUSER_MOUNT, username, sitename, 'html')
|
settings.GVAWEB_WWWUSER_MOUNT, username, sitename, 'html')
|
||||||
|
|
||||||
|
|
||||||
|
def _get_template(templatename):
|
||||||
|
return JINJAENV.get_template(templatename)
|
||||||
|
|
||||||
|
|
||||||
@shared_task
|
@shared_task
|
||||||
def create_web_vhost_config(username, sitename):
|
def create_web_vhost_config(username, sitename, wildcard):
|
||||||
"""
|
"""
|
||||||
This task creates a virtual host configuration on an nginx web
|
This task creates a virtual host configuration on an nginx web
|
||||||
server.
|
server.
|
||||||
|
|
||||||
:param str username: user who owns the site
|
:param str username: user who owns the site
|
||||||
:param str sitename: site name
|
: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
|
:return: :py:const:`True` if the creation finished successfully
|
||||||
:rtype: boolean
|
:rtype: boolean
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
conftmpl = _get_template('vhost.nginx')
|
||||||
|
confdata = conftmpl.render(
|
||||||
|
domain=sitename, user=username,
|
||||||
|
docroot=_build_document_root_path(sitename, username),
|
||||||
|
wildcard=wildcard)
|
||||||
|
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
|
@shared_task
|
||||||
|
@ -63,6 +111,17 @@ def disable_web_vhost(sitename):
|
||||||
:rtype: boolean
|
:rtype: boolean
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
try:
|
||||||
|
subprocess.check_output([
|
||||||
|
SUDO_CMD, RM_CMD, _build_enabled_vhost_path(sitename)],
|
||||||
|
stderr=subprocess.STDOUT)
|
||||||
|
subprocess.check_output([
|
||||||
|
SUDO_CMD, SERVICE_CMD, 'nginx', 'reload'],
|
||||||
|
stderr=subprocess.STDOUT)
|
||||||
|
except subprocess.CalledProcessError as cpe:
|
||||||
|
log_and_raise(
|
||||||
|
cpe, 'could not disable site configuration for %s', sitename)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
@shared_task
|
@shared_task
|
||||||
|
@ -76,6 +135,20 @@ def enable_web_vhost(sitename):
|
||||||
:rtype: boolean
|
:rtype: boolean
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
try:
|
||||||
|
subprocess.check_output([
|
||||||
|
SUDO_CMD, LN_CMD, '-s',
|
||||||
|
_build_vhost_config_path(sitename),
|
||||||
|
_build_enabled_vhost_path(sitename)],
|
||||||
|
stderr=subprocess.STDOUT)
|
||||||
|
subprocess.check_output([
|
||||||
|
SUDO_CMD, SERVICE_CMD, 'nginx', 'restart'],
|
||||||
|
stderr=subprocess.STDOUT)
|
||||||
|
except subprocess.CalledProcessError as cpe:
|
||||||
|
log_and_raise(
|
||||||
|
cpe, 'could not enable site configuration for %s', sitename)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
@shared_task
|
@shared_task
|
||||||
def delete_web_vhost_config(sitename):
|
def delete_web_vhost_config(sitename):
|
||||||
|
@ -87,6 +160,14 @@ def delete_web_vhost_config(sitename):
|
||||||
:rtype: boolean
|
:rtype: boolean
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
try:
|
||||||
|
subprocess.check_output([
|
||||||
|
SUDO_CMD, RM_CMD, _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
|
@shared_task
|
||||||
|
@ -99,6 +180,29 @@ def create_web_php_fpm_pool_config(username):
|
||||||
:rtype: boolean
|
:rtype: boolean
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
conftmpl = _get_template('fpmpool.conf')
|
||||||
|
confdata = conftmpl.render(user=username)
|
||||||
|
try:
|
||||||
|
fpmtemp, filename = mkstemp()
|
||||||
|
conffile = os.fdopen(fpmtemp, 'w')
|
||||||
|
conffile.write(confdata.encode('utf8'))
|
||||||
|
finally:
|
||||||
|
if conffile:
|
||||||
|
conffile.close()
|
||||||
|
try:
|
||||||
|
subprocess.check_output([
|
||||||
|
SUDO_CMD, INSTALL_CMD, '-o', 'root', '-g', 'root', '-m', '0644',
|
||||||
|
filename, _build_php_fpm_pool_file(username)],
|
||||||
|
stderr=subprocess.STDOUT)
|
||||||
|
subprocess.check_output([
|
||||||
|
SUDO_CMD, RM_CMD, filename], stderr=subprocess.STDOUT)
|
||||||
|
subprocess.check_output([
|
||||||
|
SUDO_CMD, SERVICE_CMD, 'php5-fpm', 'reload'],
|
||||||
|
stderr=subprocess.STDOUT)
|
||||||
|
except subprocess.CalledProcessError as cpe:
|
||||||
|
log_and_raise(cpe, 'could not configure PHP FPM for %s', username)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
@shared_task
|
@shared_task
|
||||||
def delete_web_php_fpm_pool_config(username):
|
def delete_web_php_fpm_pool_config(username):
|
||||||
|
@ -110,3 +214,14 @@ def delete_web_php_fpm_pool_config(username):
|
||||||
:rtype: boolean
|
:rtype: boolean
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
try:
|
||||||
|
subprocess.check_output([
|
||||||
|
SUDO_CMD, RM_CMD, _build_php_fpm_pool_file(username)],
|
||||||
|
stderr=subprocess.STDOUT)
|
||||||
|
subprocess.check_output([
|
||||||
|
SUDO_CMD, SERVICE_CMD, 'php5-fpm', 'reload'],
|
||||||
|
stderr=subprocess.STDOUT)
|
||||||
|
except subprocess.CalledProcessError as cpe:
|
||||||
|
log_and_raise(
|
||||||
|
cpe, 'could not delete PHP FPM configuration for %s', username)
|
||||||
|
return True
|
||||||
|
|
15
gvaweb/webtasks/templates/fpmpool.conf
Normal file
15
gvaweb/webtasks/templates/fpmpool.conf
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
[{{ user }}]
|
||||||
|
user = {{ user }}
|
||||||
|
group = {{ user }}
|
||||||
|
listen = /var/run/php5-fpm-{{ user }}.sock
|
||||||
|
listen.owner = www-data
|
||||||
|
listen.group = www-data
|
||||||
|
pm = dynamic
|
||||||
|
pm.max_children = 5
|
||||||
|
pm.start_servers = 2
|
||||||
|
pm.min_spare_servers = 1
|
||||||
|
pm.max_spare_servers = 3
|
||||||
|
pm.max_requests = 1000
|
||||||
|
chdir = /
|
||||||
|
request_slowlog_timeout = 10s
|
||||||
|
slowlog = /var/log/php5-fpm/{{ user }}.slow.log
|
29
gvaweb/webtasks/templates/vhost.nginx
Normal file
29
gvaweb/webtasks/templates/vhost.nginx
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
server {
|
||||||
|
server_name {{ domain }};
|
||||||
|
{%- if wildcard %}
|
||||||
|
server_name *.{{ domain|parentdomain }};
|
||||||
|
{%- endif %}
|
||||||
|
|
||||||
|
access_log /var/log/nginx/{{ domain }}.access.log;
|
||||||
|
error_log /var/log/nginx/{{ domain }}.error.log;
|
||||||
|
|
||||||
|
client_max_body_size 20M;
|
||||||
|
gzip on;
|
||||||
|
gzip_types text/javascript application/x-javascript text/css;
|
||||||
|
|
||||||
|
root {{ docroot }};
|
||||||
|
|
||||||
|
index index.php index.html index.htm;
|
||||||
|
|
||||||
|
location ~ ^/(.+\.php)$ {
|
||||||
|
try_files $uri =404;
|
||||||
|
fastcgi_pass unix:/var/run/php5-fpm-{{ user }}.sock;
|
||||||
|
fastcgi_index index.php;
|
||||||
|
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||||
|
include fastcgi_params;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ /\.ht {
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,3 +5,4 @@ billiard==3.3.0.19
|
||||||
celery==3.1.17
|
celery==3.1.17
|
||||||
kombu==3.0.24
|
kombu==3.0.24
|
||||||
pytz==2014.10
|
pytz==2014.10
|
||||||
|
Jinja2==2.7.3
|
||||||
|
|
Loading…
Reference in a new issue