2014-07-25 15:17:50 +00:00
|
|
|
import textwrap
|
2014-05-08 16:59:35 +00:00
|
|
|
import os
|
2014-09-26 15:05:20 +00:00
|
|
|
import re
|
2014-05-08 16:59:35 +00:00
|
|
|
|
|
|
|
from django.template import Template, Context
|
|
|
|
from django.utils.translation import ugettext_lazy as _
|
|
|
|
|
2014-07-09 16:17:43 +00:00
|
|
|
from orchestra.apps.orchestration import ServiceController
|
|
|
|
from orchestra.apps.resources import ServiceMonitor
|
2014-05-08 16:59:35 +00:00
|
|
|
|
|
|
|
from .. import settings
|
|
|
|
|
|
|
|
|
2014-07-09 16:17:43 +00:00
|
|
|
class Apache2Backend(ServiceController):
|
2014-05-08 16:59:35 +00:00
|
|
|
model = 'websites.Website'
|
2014-09-24 20:09:41 +00:00
|
|
|
related_models = (
|
|
|
|
('websites.Content', 'website'),
|
|
|
|
)
|
2014-05-08 16:59:35 +00:00
|
|
|
verbose_name = _("Apache 2")
|
|
|
|
|
|
|
|
def save(self, site):
|
|
|
|
context = self.get_context(site)
|
|
|
|
extra_conf = self.get_content_directives(site)
|
|
|
|
if site.protocol is 'https':
|
|
|
|
extra_conf += self.get_ssl(site)
|
|
|
|
extra_conf += self.get_security(site)
|
2014-10-30 16:34:02 +00:00
|
|
|
extra_conf += self.get_redirect(site)
|
2014-05-08 16:59:35 +00:00
|
|
|
context['extra_conf'] = extra_conf
|
|
|
|
|
2014-07-28 17:28:00 +00:00
|
|
|
apache_conf = Template(textwrap.dedent("""\
|
|
|
|
# {{ banner }}
|
2014-10-17 15:24:41 +00:00
|
|
|
<VirtualHost {{ ip }}:{{ site.port }}>
|
2014-10-10 14:39:46 +00:00
|
|
|
ServerName {{ site.domains.all|first }}\
|
2014-07-28 17:28:00 +00:00
|
|
|
{% if site.domains.all|slice:"1:" %}
|
2015-03-02 10:37:25 +00:00
|
|
|
ServerAlias {{ site.domains.all|slice:"1:"|join:' ' }}{% endif %}\
|
|
|
|
{% if access_log %}
|
|
|
|
CustomLog {{ access_log }} common{% endif %}\
|
|
|
|
{% if error_log %}
|
|
|
|
ErrorLog {{ error_log }}{% endif %}
|
2014-10-10 14:39:46 +00:00
|
|
|
SuexecUserGroup {{ user }} {{ group }}\
|
|
|
|
{% for line in extra_conf.splitlines %}
|
|
|
|
{{ line | safe }}{% endfor %}
|
2015-03-02 10:37:25 +00:00
|
|
|
#IncludeOptional /etc/apache2/extra-vhos[t]/{{ site_unique_name }}.con[f]
|
2014-07-28 17:28:00 +00:00
|
|
|
</VirtualHost>"""
|
|
|
|
))
|
2014-05-08 16:59:35 +00:00
|
|
|
apache_conf = apache_conf.render(Context(context))
|
|
|
|
apache_conf += self.get_protections(site)
|
|
|
|
context['apache_conf'] = apache_conf
|
|
|
|
|
2014-10-17 14:59:06 +00:00
|
|
|
self.append(textwrap.dedent("""\
|
|
|
|
{
|
|
|
|
echo -e '%(apache_conf)s' | diff -N -I'^\s*#' %(sites_available)s -
|
|
|
|
} || {
|
|
|
|
echo -e '%(apache_conf)s' > %(sites_available)s
|
|
|
|
UPDATED=1
|
2014-11-27 19:17:26 +00:00
|
|
|
}""") % context
|
|
|
|
)
|
2014-05-08 16:59:35 +00:00
|
|
|
self.enable_or_disable(site)
|
|
|
|
|
|
|
|
def delete(self, site):
|
|
|
|
context = self.get_context(site)
|
|
|
|
self.append("a2dissite %(site_unique_name)s.conf && UPDATED=1" % context)
|
|
|
|
self.append("rm -fr %(sites_available)s" % context)
|
|
|
|
|
|
|
|
def commit(self):
|
|
|
|
""" reload Apache2 if necessary """
|
2015-03-02 10:37:25 +00:00
|
|
|
self.append('[[ $UPDATED == 1 ]] && service apache2 reload || true')
|
2014-05-08 16:59:35 +00:00
|
|
|
|
|
|
|
def get_content_directives(self, site):
|
|
|
|
directives = ''
|
|
|
|
for content in site.content_set.all().order_by('-path'):
|
2014-10-24 10:16:46 +00:00
|
|
|
method, args = content.webapp.get_directive()
|
2014-05-08 16:59:35 +00:00
|
|
|
method = getattr(self, 'get_%s_directives' % method)
|
|
|
|
directives += method(content, *args)
|
|
|
|
return directives
|
|
|
|
|
2014-10-24 10:16:46 +00:00
|
|
|
def get_static_directives(self, content, *args):
|
2014-05-08 16:59:35 +00:00
|
|
|
context = self.get_content_context(content)
|
|
|
|
context['path'] = args[0] % context if args else content.webapp.get_path()
|
|
|
|
return "Alias %(location)s %(path)s\n" % context
|
|
|
|
|
|
|
|
def get_fpm_directives(self, content, *args):
|
|
|
|
context = self.get_content_context(content)
|
|
|
|
context['fcgi_path'] = args[0] % context
|
|
|
|
directive = "ProxyPassMatch ^%(location)s(.*\.php(/.*)?)$ %(fcgi_path)s$1\n"
|
|
|
|
return directive % context
|
|
|
|
|
2014-10-24 10:16:46 +00:00
|
|
|
def get_fcgi_directives(self, content, fcgid_path):
|
2014-05-08 16:59:35 +00:00
|
|
|
context = self.get_content_context(content)
|
|
|
|
context['fcgid_path'] = fcgid_path % context
|
2014-10-24 10:16:46 +00:00
|
|
|
fcgid = self.get_static_directives(content)
|
2014-10-10 14:39:46 +00:00
|
|
|
fcgid += textwrap.dedent("""\
|
|
|
|
ProxyPass %(location)s !
|
|
|
|
<Directory %(app_path)s>
|
|
|
|
Options +ExecCGI
|
|
|
|
AddHandler fcgid-script .php
|
2014-10-30 16:34:02 +00:00
|
|
|
FcgidWrapper %(fcgid_path)s\
|
2014-11-27 19:17:26 +00:00
|
|
|
""") % context
|
2014-05-08 16:59:35 +00:00
|
|
|
for option in content.webapp.options.filter(name__startswith='Fcgid'):
|
|
|
|
fcgid += " %s %s\n" % (option.name, option.value)
|
|
|
|
fcgid += "</Directory>\n"
|
|
|
|
return fcgid
|
|
|
|
|
|
|
|
def get_ssl(self, site):
|
|
|
|
cert = settings.WEBSITES_DEFAULT_HTTPS_CERT
|
|
|
|
custom_cert = site.options.filter(name='ssl')
|
|
|
|
if custom_cert:
|
|
|
|
cert = tuple(custom_cert[0].value.split())
|
2014-10-30 16:34:02 +00:00
|
|
|
# TODO separate directtives?
|
2014-10-10 14:39:46 +00:00
|
|
|
directives = textwrap.dedent("""\
|
|
|
|
SSLEngine on
|
|
|
|
SSLCertificateFile %s
|
2014-10-30 16:34:02 +00:00
|
|
|
SSLCertificateKeyFile %s\
|
|
|
|
""" % cert
|
2014-10-10 14:39:46 +00:00
|
|
|
)
|
2014-05-08 16:59:35 +00:00
|
|
|
return directives
|
|
|
|
|
|
|
|
def get_security(self, site):
|
|
|
|
directives = ''
|
|
|
|
for rules in site.options.filter(name='sec_rule_remove'):
|
2014-10-17 14:59:06 +00:00
|
|
|
for rule in rules.value.split():
|
2014-10-30 16:34:02 +00:00
|
|
|
directives += "SecRuleRemoveById %i\n" % int(rule)
|
2014-05-08 16:59:35 +00:00
|
|
|
for modsecurity in site.options.filter(name='sec_rule_off'):
|
2014-10-14 13:50:19 +00:00
|
|
|
directives += textwrap.dedent("""\
|
|
|
|
<LocationMatch %s>
|
|
|
|
SecRuleEngine Off
|
2014-10-30 16:34:02 +00:00
|
|
|
</LocationMatch>\
|
2014-10-14 13:50:19 +00:00
|
|
|
""" % modsecurity.value)
|
2014-10-30 16:34:02 +00:00
|
|
|
if directives:
|
|
|
|
directives = '<IfModule mod_security2.c>\n%s\n</IfModule>' % directives
|
|
|
|
return directives
|
|
|
|
|
|
|
|
def get_redirect(self, site):
|
|
|
|
directives = ''
|
|
|
|
for redirect in site.options.filter(name='redirect'):
|
|
|
|
if re.match(r'^.*[\^\*\$\?\)]+.*$', redirect.value):
|
|
|
|
directives += "RedirectMatch %s" % redirect.value
|
|
|
|
else:
|
|
|
|
directives += "Redirect %s" % redirect.value
|
2014-05-08 16:59:35 +00:00
|
|
|
return directives
|
|
|
|
|
|
|
|
def get_protections(self, site):
|
2014-11-10 17:18:04 +00:00
|
|
|
protections = ''
|
2014-09-26 15:05:20 +00:00
|
|
|
context = self.get_context(site)
|
2014-05-08 16:59:35 +00:00
|
|
|
for protection in site.options.filter(name='directory_protection'):
|
2014-11-10 17:18:04 +00:00
|
|
|
path, name, passwd = protection.value.split()
|
2014-05-08 16:59:35 +00:00
|
|
|
path = os.path.join(context['root'], path)
|
|
|
|
passwd = os.path.join(self.USER_HOME % context, passwd)
|
2014-10-10 14:39:46 +00:00
|
|
|
protections += textwrap.dedent("""
|
|
|
|
<Directory %s>
|
|
|
|
AllowOverride All
|
|
|
|
#AuthPAM_Enabled off
|
|
|
|
AuthType Basic
|
|
|
|
AuthName %s
|
|
|
|
AuthUserFile %s
|
|
|
|
<Limit GET POST>
|
|
|
|
require valid-user
|
|
|
|
</Limit>
|
|
|
|
</Directory>""" % (path, name, passwd)
|
2014-05-08 16:59:35 +00:00
|
|
|
)
|
|
|
|
return protections
|
|
|
|
|
|
|
|
def enable_or_disable(self, site):
|
|
|
|
context = self.get_context(site)
|
|
|
|
if site.is_active:
|
2015-03-02 10:37:25 +00:00
|
|
|
self.append(textwrap.dedent("""\
|
|
|
|
if [[ ! -f %(sites_enabled)s ]]; then
|
|
|
|
a2ensite %(site_unique_name)s.conf
|
|
|
|
else
|
|
|
|
UPDATED=0
|
|
|
|
fi""" % context
|
|
|
|
))
|
2014-05-08 16:59:35 +00:00
|
|
|
else:
|
2015-03-02 10:37:25 +00:00
|
|
|
self.append(textwrap.dedent("""\
|
|
|
|
if [[ -f %(sites_enabled)s ]]; then
|
|
|
|
a2dissite %(site_unique_name)s.conf;
|
|
|
|
else
|
|
|
|
UPDATED=0
|
|
|
|
fi""" % context
|
|
|
|
))
|
2014-05-08 16:59:35 +00:00
|
|
|
|
2014-11-10 15:03:34 +00:00
|
|
|
def get_username(self, site):
|
2014-11-10 16:25:45 +00:00
|
|
|
option = site.options.filter(name='user_group').first()
|
2014-11-10 15:03:34 +00:00
|
|
|
if option:
|
2014-11-10 16:25:45 +00:00
|
|
|
return option.value.split()[0]
|
2014-11-10 15:03:34 +00:00
|
|
|
return site.account.username
|
|
|
|
|
|
|
|
def get_groupname(self, site):
|
2014-11-10 16:25:45 +00:00
|
|
|
option = site.options.filter(name='user_group').first()
|
|
|
|
if option and ' ' in option.value:
|
|
|
|
user, group = option.value.split()
|
2014-11-10 15:03:34 +00:00
|
|
|
return group
|
|
|
|
return site.account.username
|
|
|
|
|
2014-05-08 16:59:35 +00:00
|
|
|
def get_context(self, site):
|
|
|
|
base_apache_conf = settings.WEBSITES_BASE_APACHE_CONF
|
|
|
|
sites_available = os.path.join(base_apache_conf, 'sites-available')
|
|
|
|
sites_enabled = os.path.join(base_apache_conf, 'sites-enabled')
|
|
|
|
context = {
|
|
|
|
'site': site,
|
|
|
|
'site_name': site.name,
|
2014-10-17 15:23:02 +00:00
|
|
|
'ip': settings.WEBSITES_DEFAULT_IP,
|
2014-05-08 16:59:35 +00:00
|
|
|
'site_unique_name': site.unique_name,
|
2014-11-10 15:03:34 +00:00
|
|
|
'user': self.get_username(site),
|
|
|
|
'group': self.get_groupname(site),
|
2015-03-02 10:37:25 +00:00
|
|
|
'sites_enabled': "%s.conf" % os.path.join(sites_enabled, site.unique_name),
|
2014-05-08 16:59:35 +00:00
|
|
|
'sites_available': "%s.conf" % os.path.join(sites_available, site.unique_name),
|
2015-03-02 10:37:25 +00:00
|
|
|
'access_log': site.get_www_access_log_path(),
|
|
|
|
'error_log': site.get_www_error_log_path(),
|
2014-05-08 16:59:35 +00:00
|
|
|
'banner': self.get_banner(),
|
|
|
|
}
|
|
|
|
return context
|
|
|
|
|
|
|
|
def get_content_context(self, content):
|
|
|
|
context = self.get_context(content.website)
|
|
|
|
context.update({
|
|
|
|
'type': content.webapp.type,
|
|
|
|
'location': content.path,
|
|
|
|
'app_name': content.webapp.name,
|
|
|
|
'app_path': content.webapp.get_path(),
|
|
|
|
'fpm_port': content.webapp.get_fpm_port(),
|
|
|
|
})
|
|
|
|
return context
|
2014-07-09 16:17:43 +00:00
|
|
|
|
|
|
|
|
|
|
|
class Apache2Traffic(ServiceMonitor):
|
|
|
|
model = 'websites.Website'
|
|
|
|
resource = ServiceMonitor.TRAFFIC
|
|
|
|
verbose_name = _("Apache 2 Traffic")
|
|
|
|
|
2014-07-25 15:17:50 +00:00
|
|
|
def prepare(self):
|
2014-11-21 13:53:39 +00:00
|
|
|
super(Apache2Traffic, self).prepare()
|
2014-11-20 15:34:59 +00:00
|
|
|
ignore_hosts = '\\|'.join(settings.WEBSITES_TRAFFIC_IGNORE_HOSTS)
|
|
|
|
context = {
|
|
|
|
'current_date': self.current_date.strftime("%Y-%m-%d %H:%M:%S %Z"),
|
|
|
|
'ignore_hosts': '-v "%s"' % ignore_hosts if ignore_hosts else '',
|
|
|
|
}
|
2014-10-10 14:39:46 +00:00
|
|
|
self.append(textwrap.dedent("""\
|
2014-07-25 15:17:50 +00:00
|
|
|
function monitor () {
|
|
|
|
OBJECT_ID=$1
|
2014-11-20 15:34:59 +00:00
|
|
|
INI_DATE=$(date "+%%Y%%m%%d%%H%%M%%S" -d "$2")
|
|
|
|
END_DATE=$(date '+%%Y%%m%%d%%H%%M%%S' -d '%(current_date)s')
|
2014-07-25 15:17:50 +00:00
|
|
|
LOG_FILE="$3"
|
|
|
|
{
|
2015-03-02 10:37:25 +00:00
|
|
|
{ grep %(ignore_hosts)s ${LOG_FILE} || echo -e '\\r'; } \\
|
2014-11-20 15:34:59 +00:00
|
|
|
| awk -v ini="${INI_DATE}" -v end="${END_DATE}" '
|
|
|
|
BEGIN {
|
|
|
|
sum = 0
|
2015-03-02 10:37:25 +00:00
|
|
|
months["Jan"] = "01"
|
|
|
|
months["Feb"] = "02"
|
|
|
|
months["Mar"] = "03"
|
|
|
|
months["Apr"] = "04"
|
|
|
|
months["May"] = "05"
|
|
|
|
months["Jun"] = "06"
|
|
|
|
months["Jul"] = "07"
|
|
|
|
months["Aug"] = "08"
|
|
|
|
months["Sep"] = "09"
|
|
|
|
months["Oct"] = "10"
|
|
|
|
months["Nov"] = "11"
|
|
|
|
months["Dec"] = "12"
|
2014-11-20 15:34:59 +00:00
|
|
|
} {
|
|
|
|
# date = [11/Jul/2014:13:50:41
|
|
|
|
date = substr($4, 2)
|
|
|
|
year = substr(date, 8, 4)
|
|
|
|
month = months[substr(date, 4, 3)];
|
|
|
|
day = substr(date, 1, 2)
|
|
|
|
hour = substr(date, 13, 2)
|
|
|
|
minute = substr(date, 16, 2)
|
|
|
|
second = substr(date, 19, 2)
|
|
|
|
line_date = year month day hour minute second
|
|
|
|
if ( line_date > ini && line_date < end)
|
|
|
|
sum += $NF
|
|
|
|
} END {
|
|
|
|
print sum
|
|
|
|
}' || [[ $? == 1 ]] && true
|
2014-07-25 15:17:50 +00:00
|
|
|
} | xargs echo ${OBJECT_ID}
|
2014-11-20 15:34:59 +00:00
|
|
|
}""" % context))
|
2014-07-25 15:17:50 +00:00
|
|
|
|
2014-07-09 16:17:43 +00:00
|
|
|
def monitor(self, site):
|
|
|
|
context = self.get_context(site)
|
2014-11-20 15:34:59 +00:00
|
|
|
self.append('monitor {object_id} "{last_date}" {log_file}'.format(**context))
|
2014-07-09 16:17:43 +00:00
|
|
|
|
|
|
|
def get_context(self, site):
|
|
|
|
return {
|
2014-10-27 14:31:04 +00:00
|
|
|
'log_file': '%s{,.1}' % site.get_www_log_path(),
|
2014-10-27 17:34:14 +00:00
|
|
|
'last_date': self.get_last_date(site.pk).strftime("%Y-%m-%d %H:%M:%S %Z"),
|
2014-07-11 14:48:46 +00:00
|
|
|
'object_id': site.pk,
|
2014-07-09 16:17:43 +00:00
|
|
|
}
|