Fixes on website apache backend
This commit is contained in:
parent
44e8b29b43
commit
340a40262f
|
@ -7,7 +7,9 @@ from django.utils import timezone
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from orchestra.apps.orchestration import ServiceController
|
from orchestra.apps.orchestration import ServiceController
|
||||||
|
from orchestra.apps.systemusers.backends import SystemUserBackend
|
||||||
from orchestra.apps.resources import ServiceMonitor
|
from orchestra.apps.resources import ServiceMonitor
|
||||||
|
from orchestra.utils.humanize import unit_to_bytes
|
||||||
|
|
||||||
from . import settings
|
from . import settings
|
||||||
from .models import Address
|
from .models import Address
|
||||||
|
@ -20,6 +22,59 @@ from .models import Address
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class MailSystemUserBackend(ServiceController):
|
||||||
|
verbose_name = _("Mail system users")
|
||||||
|
model = 'mailboxes.Mailbox'
|
||||||
|
|
||||||
|
def save(self, mailbox):
|
||||||
|
context = self.get_context(mailbox)
|
||||||
|
self.append(textwrap.dedent("""
|
||||||
|
if [[ $( id %(user)s ) ]]; then
|
||||||
|
usermod %(user)s --password '%(password)s' --shell %(initial_shell)s
|
||||||
|
else
|
||||||
|
useradd %(user)s --home %(home)s --password '%(password)s'
|
||||||
|
fi
|
||||||
|
mkdir -p %(home)s
|
||||||
|
chmod 751 %(home)s
|
||||||
|
chown %(user)s:%(group)s %(home)s""") % context
|
||||||
|
)
|
||||||
|
if hasattr(mailbox, 'resources') and hasattr(mailbox.resources, 'disk'):
|
||||||
|
self.set_quota(mailbox, context)
|
||||||
|
|
||||||
|
def set_quota(self, mailbox, context):
|
||||||
|
context['quota'] = mailbox.resources.disk.allocated * unit_to_bytes(mailbox.resources.disk.unit)
|
||||||
|
self.append(textwrap.dedent("""
|
||||||
|
mkdir -p %(home)s/Maildir
|
||||||
|
chown %(user)s:%(group)s %(home)s/Maildir
|
||||||
|
if [[ ! -f %(home)s/Maildir/maildirsize ]]; then
|
||||||
|
echo "%(quota)iS" > %(home)s/Maildir/maildirsize
|
||||||
|
chown %(user)s:%(group)s %(home)s/Maildir/maildirsize
|
||||||
|
else
|
||||||
|
sed -i '1s/.*/%(quota)iS/' %(home)s/Maildir/maildirsize
|
||||||
|
fi""") % context
|
||||||
|
)
|
||||||
|
|
||||||
|
def delete(self, mailbox):
|
||||||
|
context = self.get_context(mailbox)
|
||||||
|
self.append(textwrap.dedent("""
|
||||||
|
{ sleep 2 && killall -u %(user)s -s KILL; } &
|
||||||
|
killall -u %(user)s || true
|
||||||
|
userdel %(user)s || true
|
||||||
|
groupdel %(user)s || true""") % context
|
||||||
|
)
|
||||||
|
self.append('mv %(home)s %(home)s.deleted' % context)
|
||||||
|
|
||||||
|
def get_context(self, mailbox):
|
||||||
|
context = {
|
||||||
|
'user': mailbox.name,
|
||||||
|
'group': mailbox.name,
|
||||||
|
'password': mailbox.password if mailbox.active else '*%s' % mailbox.password,
|
||||||
|
'home': mailbox.get_home(),
|
||||||
|
'initial_shell': '/dev/null',
|
||||||
|
}
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
class PasswdVirtualUserBackend(ServiceController):
|
class PasswdVirtualUserBackend(ServiceController):
|
||||||
verbose_name = _("Mail virtual user (passwd-file)")
|
verbose_name = _("Mail virtual user (passwd-file)")
|
||||||
model = 'mailboxes.Mailbox'
|
model = 'mailboxes.Mailbox'
|
||||||
|
@ -29,8 +84,8 @@ class PasswdVirtualUserBackend(ServiceController):
|
||||||
|
|
||||||
def set_user(self, context):
|
def set_user(self, context):
|
||||||
self.append(textwrap.dedent("""
|
self.append(textwrap.dedent("""
|
||||||
if [[ $( grep "^%(username)s:" %(passwd_path)s ) ]]; then
|
if [[ $( grep "^%(user)s:" %(passwd_path)s ) ]]; then
|
||||||
sed -i 's#^%(username)s:.*#%(passwd)s#' %(passwd_path)s
|
sed -i 's#^%(user)s:.*#%(passwd)s#' %(passwd_path)s
|
||||||
else
|
else
|
||||||
echo '%(passwd)s' >> %(passwd_path)s
|
echo '%(passwd)s' >> %(passwd_path)s
|
||||||
fi""") % context
|
fi""") % context
|
||||||
|
@ -40,14 +95,14 @@ class PasswdVirtualUserBackend(ServiceController):
|
||||||
|
|
||||||
def set_mailbox(self, context):
|
def set_mailbox(self, context):
|
||||||
self.append(textwrap.dedent("""
|
self.append(textwrap.dedent("""
|
||||||
if [[ ! $(grep "^%(username)s@%(mailbox_domain)s\s" %(virtual_mailbox_maps)s) ]]; then
|
if [[ ! $(grep "^%(user)s@%(mailbox_domain)s\s" %(virtual_mailbox_maps)s) ]]; then
|
||||||
echo "%(username)s@%(mailbox_domain)s\tOK" >> %(virtual_mailbox_maps)s
|
echo "%(user)s@%(mailbox_domain)s\tOK" >> %(virtual_mailbox_maps)s
|
||||||
UPDATED_VIRTUAL_MAILBOX_MAPS=1
|
UPDATED_VIRTUAL_MAILBOX_MAPS=1
|
||||||
fi""") % context
|
fi""") % context
|
||||||
)
|
)
|
||||||
|
|
||||||
def generate_filter(self, mailbox, context):
|
def generate_filter(self, mailbox, context):
|
||||||
self.append("doveadm mailbox create -u %(username)s Spam" % context)
|
self.append("doveadm mailbox create -u %(user)s Spam" % context)
|
||||||
context['filtering_path'] = settings.MAILBOXES_SIEVE_PATH % context
|
context['filtering_path'] = settings.MAILBOXES_SIEVE_PATH % context
|
||||||
filtering = mailbox.get_filtering()
|
filtering = mailbox.get_filtering()
|
||||||
if filtering:
|
if filtering:
|
||||||
|
@ -67,8 +122,8 @@ class PasswdVirtualUserBackend(ServiceController):
|
||||||
context = self.get_context(mailbox)
|
context = self.get_context(mailbox)
|
||||||
self.append("{ sleep 2 && killall -u %(uid)s -s KILL; } &" % context)
|
self.append("{ sleep 2 && killall -u %(uid)s -s KILL; } &" % context)
|
||||||
self.append("killall -u %(uid)s || true" % context)
|
self.append("killall -u %(uid)s || true" % context)
|
||||||
self.append("sed -i '/^%(username)s:.*/d' %(passwd_path)s" % context)
|
self.append("sed -i '/^%(user)s:.*/d' %(passwd_path)s" % context)
|
||||||
self.append("sed -i '/^%(username)s@%(mailbox_domain)s\s.*/d' %(virtual_mailbox_maps)s" % context)
|
self.append("sed -i '/^%(user)s@%(mailbox_domain)s\s.*/d' %(virtual_mailbox_maps)s" % context)
|
||||||
self.append("UPDATED_VIRTUAL_MAILBOX_MAPS=1")
|
self.append("UPDATED_VIRTUAL_MAILBOX_MAPS=1")
|
||||||
# TODO delete
|
# TODO delete
|
||||||
context['deleted'] = context['home'].rstrip('/') + '.deleted'
|
context['deleted'] = context['home'].rstrip('/') + '.deleted'
|
||||||
|
@ -99,7 +154,7 @@ class PasswdVirtualUserBackend(ServiceController):
|
||||||
def get_context(self, mailbox):
|
def get_context(self, mailbox):
|
||||||
context = {
|
context = {
|
||||||
'name': mailbox.name,
|
'name': mailbox.name,
|
||||||
'username': mailbox.name,
|
'user': mailbox.name,
|
||||||
'password': mailbox.password if mailbox.active else '*%s' % mailbox.password,
|
'password': mailbox.password if mailbox.active else '*%s' % mailbox.password,
|
||||||
'uid': 10000 + mailbox.pk,
|
'uid': 10000 + mailbox.pk,
|
||||||
'gid': 10000 + mailbox.pk,
|
'gid': 10000 + mailbox.pk,
|
||||||
|
@ -112,7 +167,7 @@ class PasswdVirtualUserBackend(ServiceController):
|
||||||
'mailbox_domain': settings.MAILBOXES_VIRTUAL_MAILBOX_DEFAULT_DOMAIN,
|
'mailbox_domain': settings.MAILBOXES_VIRTUAL_MAILBOX_DEFAULT_DOMAIN,
|
||||||
}
|
}
|
||||||
context['extra_fields'] = self.get_extra_fields(mailbox, context)
|
context['extra_fields'] = self.get_extra_fields(mailbox, context)
|
||||||
context['passwd'] = '{username}:{password}:{uid}:{gid}::{home}::{extra_fields}'.format(**context)
|
context['passwd'] = '{user}:{password}:{uid}:{gid}::{home}::{extra_fields}'.format(**context)
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ from .backends import ServiceBackend
|
||||||
from .models import Server, Route, BackendLog, BackendOperation
|
from .models import Server, Route, BackendLog, BackendOperation
|
||||||
from .widgets import RouteBackendSelect
|
from .widgets import RouteBackendSelect
|
||||||
|
|
||||||
|
|
||||||
STATE_COLORS = {
|
STATE_COLORS = {
|
||||||
BackendLog.RECEIVED: 'darkorange',
|
BackendLog.RECEIVED: 'darkorange',
|
||||||
BackendLog.TIMEOUT: 'red',
|
BackendLog.TIMEOUT: 'red',
|
||||||
|
|
|
@ -140,7 +140,7 @@ class ServiceBackend(plugins.Plugin):
|
||||||
return list(scripts.iteritems())
|
return list(scripts.iteritems())
|
||||||
|
|
||||||
def get_banner(self):
|
def get_banner(self):
|
||||||
time = timezone.now().strftime("%h %d, %Y %I:%M:%S")
|
time = timezone.now().strftime("%h %d, %Y %I:%M:%S %Z")
|
||||||
return "Generated by Orchestra at %s" % time
|
return "Generated by Orchestra at %s" % time
|
||||||
|
|
||||||
def execute(self, server, async=False):
|
def execute(self, server, async=False):
|
||||||
|
|
|
@ -19,28 +19,28 @@ class SystemUserBackend(ServiceController):
|
||||||
groups = ','.join(self.get_groups(user))
|
groups = ','.join(self.get_groups(user))
|
||||||
context['groups_arg'] = '--groups %s' % groups if groups else ''
|
context['groups_arg'] = '--groups %s' % groups if groups else ''
|
||||||
self.append(textwrap.dedent("""
|
self.append(textwrap.dedent("""
|
||||||
if [[ $( id %(username)s ) ]]; then
|
if [[ $( id %(user)s ) ]]; then
|
||||||
usermod %(username)s --password '%(password)s' --shell %(shell)s %(groups_arg)s
|
usermod %(user)s --password '%(password)s' --shell %(shell)s %(groups_arg)s
|
||||||
else
|
else
|
||||||
useradd %(username)s --home %(home)s --password '%(password)s' --shell %(shell)s %(groups_arg)s
|
useradd %(user)s --home %(home)s --password '%(password)s' --shell %(shell)s %(groups_arg)s
|
||||||
fi
|
fi
|
||||||
mkdir -p %(home)s
|
mkdir -p %(home)s
|
||||||
chmod 750 %(home)s
|
chmod 750 %(home)s
|
||||||
chown %(username)s:%(username)s %(home)s""") % context
|
chown %(user)s:%(user)s %(home)s""") % context
|
||||||
)
|
)
|
||||||
for member in settings.SYSTEMUSERS_DEFAULT_GROUP_MEMBERS:
|
for member in settings.SYSTEMUSERS_DEFAULT_GROUP_MEMBERS:
|
||||||
context['member'] = member
|
context['member'] = member
|
||||||
self.append('usermod -a -G %(username)s %(member)s' % context)
|
self.append('usermod -a -G %(user)s %(member)s' % context)
|
||||||
if not user.is_main:
|
if not user.is_main:
|
||||||
self.append('usermod -a -G %(username)s %(mainusername)s' % context)
|
self.append('usermod -a -G %(user)s %(mainuser)s' % context)
|
||||||
|
|
||||||
def delete(self, user):
|
def delete(self, user):
|
||||||
context = self.get_context(user)
|
context = self.get_context(user)
|
||||||
self.append(textwrap.dedent("""\
|
self.append(textwrap.dedent("""\
|
||||||
{ sleep 2 && killall -u %(username)s -s KILL; } &
|
{ sleep 2 && killall -u %(user)s -s KILL; } &
|
||||||
killall -u %(username)s || true
|
killall -u %(user)s || true
|
||||||
userdel %(username)s || true
|
userdel %(user)s || true
|
||||||
groupdel %(username)s || true""") % context
|
groupdel %(group)s || true""") % context
|
||||||
)
|
)
|
||||||
self.delete_home(context, user)
|
self.delete_home(context, user)
|
||||||
|
|
||||||
|
@ -51,8 +51,7 @@ class SystemUserBackend(ServiceController):
|
||||||
def delete_home(self, context, user):
|
def delete_home(self, context, user):
|
||||||
if user.home.rstrip('/') == user.get_base_home().rstrip('/'):
|
if user.home.rstrip('/') == user.get_base_home().rstrip('/'):
|
||||||
# TODO delete instead of this shit
|
# TODO delete instead of this shit
|
||||||
context['deleted'] = context['home'].rstrip('/') + '.deleted'
|
self.append("mv %(home)s %(home)s.deleted" % context)
|
||||||
self.append("mv %(home)s %(deleted)s" % context)
|
|
||||||
|
|
||||||
def get_groups(self, user):
|
def get_groups(self, user):
|
||||||
if user.is_main:
|
if user.is_main:
|
||||||
|
@ -62,10 +61,11 @@ class SystemUserBackend(ServiceController):
|
||||||
def get_context(self, user):
|
def get_context(self, user):
|
||||||
context = {
|
context = {
|
||||||
'object_id': user.pk,
|
'object_id': user.pk,
|
||||||
'username': user.username,
|
'user': user.username,
|
||||||
|
'group': user.username,
|
||||||
'password': user.password if user.active else '*%s' % user.password,
|
'password': user.password if user.active else '*%s' % user.password,
|
||||||
'shell': user.shell,
|
'shell': user.shell,
|
||||||
'mainusername': user.username if user.is_main else user.account.username,
|
'mainuser': user.username if user.is_main else user.account.username,
|
||||||
'home': user.get_home()
|
'home': user.get_home()
|
||||||
}
|
}
|
||||||
return context
|
return context
|
||||||
|
|
|
@ -122,6 +122,7 @@ class SystemUser(models.Model):
|
||||||
|
|
||||||
def get_base_home(self):
|
def get_base_home(self):
|
||||||
context = {
|
context = {
|
||||||
|
'user': self.username,
|
||||||
'username': self.username,
|
'username': self.username,
|
||||||
}
|
}
|
||||||
return os.path.normpath(settings.SYSTEMUSERS_HOME % context)
|
return os.path.normpath(settings.SYSTEMUSERS_HOME % context)
|
||||||
|
|
|
@ -20,7 +20,7 @@ SYSTEMUSERS_DISABLED_SHELLS = getattr(settings, 'SYSTEMUSERS_DISABLED_SHELLS', (
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
SYSTEMUSERS_HOME = getattr(settings, 'SYSTEMUSERS_HOME', '/home/./%(username)s')
|
SYSTEMUSERS_HOME = getattr(settings, 'SYSTEMUSERS_HOME', '/home/./%(user)s')
|
||||||
|
|
||||||
|
|
||||||
SYSTEMUSERS_FTP_LOG_PATH = getattr(settings, 'SYSTEMUSERS_FTP_LOG_PATH', '/var/log/vsftpd.log')
|
SYSTEMUSERS_FTP_LOG_PATH = getattr(settings, 'SYSTEMUSERS_FTP_LOG_PATH', '/var/log/vsftpd.log')
|
||||||
|
|
|
@ -40,7 +40,8 @@ class PHPFcgidBackend(WebAppServiceMixin, ServiceController):
|
||||||
|
|
||||||
def delete(self, webapp):
|
def delete(self, webapp):
|
||||||
context = self.get_context(webapp)
|
context = self.get_context(webapp)
|
||||||
self.append("rm '%(wrapper_path)s'" % context)
|
self.append("rm -f '%(wrapper_path)s'" % context)
|
||||||
|
self.append("rm -f '%(cmd_options_path)s'" % context)
|
||||||
self.delete_webapp_dir(context)
|
self.delete_webapp_dir(context)
|
||||||
|
|
||||||
def commit(self):
|
def commit(self):
|
||||||
|
@ -75,7 +76,8 @@ class PHPFcgidBackend(WebAppServiceMixin, ServiceController):
|
||||||
if value:
|
if value:
|
||||||
cmd_options.append("%s %s" % (directive, value))
|
cmd_options.append("%s %s" % (directive, value))
|
||||||
if cmd_options:
|
if cmd_options:
|
||||||
cmd_options.insert(0, 'FcgidCmdOptions %(wrapper_path)s' % context)
|
head = '# %(banner)s\nFcgidCmdOptions %(wrapper_path)s' % context
|
||||||
|
cmd_options.insert(0, head)
|
||||||
return ' \\\n '.join(cmd_options)
|
return ' \\\n '.join(cmd_options)
|
||||||
|
|
||||||
def get_context(self, webapp):
|
def get_context(self, webapp):
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from orchestra.apps.orchestration import ServiceController
|
||||||
|
|
||||||
|
from . import WebAppServiceMixin
|
||||||
|
|
||||||
|
|
||||||
|
class WebalizerAppBackend(WebAppServiceMixin, ServiceController):
|
||||||
|
""" Needed for cleaning up webalizer main folder when webapp deleteion withou related contents """
|
||||||
|
verbose_name = _("Webalizer App")
|
||||||
|
default_route_match = "webapp.type == 'webalizer'"
|
||||||
|
|
||||||
|
def save(self, webapp):
|
||||||
|
context = self.get_context(webapp)
|
||||||
|
self.create_webapp_dir(context)
|
||||||
|
|
||||||
|
def delete(self, webapp):
|
||||||
|
context = self.get_context(webapp)
|
||||||
|
self.delete_webapp_dir(context)
|
|
@ -0,0 +1,26 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import models, migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('webapps', '0002_webapp_data'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='webapp',
|
||||||
|
name='type',
|
||||||
|
field=models.CharField(max_length=32, verbose_name='type', choices=[(b'dokuwiki-mu', b'DokuWiki (SaaS)'), (b'drupal-mu', b'Drupdal (SaaS)'), (b'php4-fcgid', b'PHP 4 FCGID'), (b'php5.2-fcgid', b'PHP 5.2 FCGID'), (b'php5.3-fcgid', b'PHP 5.3 FCGID'), (b'php5.4-fpm', b'PHP 5.4 FPM'), (b'static', b'Static'), (b'symbolic-link', b'Symbolic link'), (b'webalizer', b'Webalizer'), (b'wordpress', b'WordPress'), (b'wordpress-mu', b'WordPress (SaaS)')]),
|
||||||
|
preserve_default=True,
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='webappoption',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(max_length=128, verbose_name='name', choices=[(None, b'-------'), (b'FileSystem', [(b'public-root', 'Public root')]), (b'Process', [(b'timeout', 'Process timeout'), (b'processes', 'Number of processes')]), (b'PHP', [(b'enabled_functions', 'Enabled functions'), (b'allow_url_include', 'Allow URL include'), (b'allow_url_fopen', 'Allow URL fopen'), (b'auto_append_file', 'Auto append file'), (b'auto_prepend_file', 'Auto prepend file'), (b'date.timezone', 'date.timezone'), (b'default_socket_timeout', 'Default socket timeout'), (b'display_errors', 'Display errors'), (b'extension', 'Extension'), (b'magic_quotes_gpc', 'Magic quotes GPC'), (b'magic_quotes_runtime', 'Magic quotes runtime'), (b'magic_quotes_sybase', 'Magic quotes sybase'), (b'max_execution_time', 'Max execution time'), (b'max_input_time', 'Max input time'), (b'max_input_vars', 'Max input vars'), (b'memory_limit', 'Memory limit'), (b'mysql.connect_timeout', 'Mysql connect timeout'), (b'output_buffering', 'Output buffering'), (b'register_globals', 'Register globals'), (b'post_max_size', 'zend_extension'), (b'sendmail_path', 'sendmail_path'), (b'session.bug_compat_warn', 'session.bug_compat_warn'), (b'session.auto_start', 'session.auto_start'), (b'safe_mode', 'Safe mode'), (b'suhosin.post.max_vars', 'Suhosin POST max vars'), (b'suhosin.get.max_vars', 'Suhosin GET max vars'), (b'suhosin.request.max_vars', 'Suhosin request max vars'), (b'suhosin.session.encrypt', 'suhosin.session.encrypt'), (b'suhosin.simulation', 'Suhosin simulation'), (b'suhosin.executor.include.whitelist', 'suhosin.executor.include.whitelist'), (b'upload_max_filesize', 'upload_max_filesize'), (b'post_max_size', 'zend_extension')])]),
|
||||||
|
preserve_default=True,
|
||||||
|
),
|
||||||
|
]
|
|
@ -1,3 +1,4 @@
|
||||||
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
|
@ -68,7 +69,7 @@ class WebApp(models.Model):
|
||||||
public_root = self.options.filter(name='public-root').first()
|
public_root = self.options.filter(name='public-root').first()
|
||||||
if public_root:
|
if public_root:
|
||||||
path = os.path.join(path, public_root.value)
|
path = os.path.join(path, public_root.value)
|
||||||
return path.replace('//', '/')
|
return os.path.normpath(path.replace('//', '/'))
|
||||||
|
|
||||||
def get_user(self):
|
def get_user(self):
|
||||||
return self.account.main_systemuser
|
return self.account.main_systemuser
|
||||||
|
|
|
@ -167,7 +167,8 @@ class PHPAppType(AppType):
|
||||||
init_vars['dissabled_functions'] = ','.join(disabled_functions)
|
init_vars['dissabled_functions'] = ','.join(disabled_functions)
|
||||||
if settings.WEBAPPS_PHP_ERROR_LOG_PATH and 'error_log' not in init_vars:
|
if settings.WEBAPPS_PHP_ERROR_LOG_PATH and 'error_log' not in init_vars:
|
||||||
context = self.get_context(webapp)
|
context = self.get_context(webapp)
|
||||||
init_vars['error_log'] = settings.WEBAPPS_PHP_ERROR_LOG_PATH % context
|
error_log_path = os.path.normpath(settings.WEBAPPS_PHP_ERROR_LOG_PATH % context)
|
||||||
|
init_vars['error_log'] = error_log_path
|
||||||
return init_vars
|
return init_vars
|
||||||
|
|
||||||
|
|
||||||
|
@ -192,7 +193,7 @@ class PHP53App(PHPAppType):
|
||||||
|
|
||||||
def get_directive(self, webapp):
|
def get_directive(self, webapp):
|
||||||
context = self.get_directive_context(webapp)
|
context = self.get_directive_context(webapp)
|
||||||
wrapper_path = settings.WEBAPPS_FCGID_PATH % context
|
wrapper_path = os.path.normpath(settings.WEBAPPS_FCGID_PATH % context)
|
||||||
return ('fcgid', webapp.get_path(), wrapper_path)
|
return ('fcgid', webapp.get_path(), wrapper_path)
|
||||||
|
|
||||||
|
|
||||||
|
@ -236,7 +237,9 @@ class WebalizerApp(AppType):
|
||||||
option_groups = ()
|
option_groups = ()
|
||||||
|
|
||||||
def get_directive(self, webapp):
|
def get_directive(self, webapp):
|
||||||
return ('static', os.path.join(webapp.get_path(), '%(site_name)s/'))
|
webalizer_path = os.path.join(webapp.get_path(), '%(site_name)s')
|
||||||
|
webalizer_path = os.path.normpath(webalizer_path)
|
||||||
|
return ('static', webalizer_path)
|
||||||
|
|
||||||
|
|
||||||
class WordPressMuApp(PHPAppType):
|
class WordPressMuApp(PHPAppType):
|
||||||
|
|
|
@ -59,14 +59,14 @@ class ContentInline(AccountAdminMixin, admin.TabularInline):
|
||||||
|
|
||||||
class WebsiteAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
class WebsiteAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = ('name', 'display_domains', 'display_webapps', 'account_link')
|
list_display = ('name', 'display_domains', 'display_webapps', 'account_link')
|
||||||
list_filter = ('port', 'is_active')
|
list_filter = ('protocol', 'is_active',)
|
||||||
change_readonly_fields = ('name',)
|
change_readonly_fields = ('name',)
|
||||||
inlines = [ContentInline, DirectiveInline]
|
inlines = [ContentInline, DirectiveInline]
|
||||||
filter_horizontal = ['domains']
|
filter_horizontal = ['domains']
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, {
|
(None, {
|
||||||
'classes': ('extrapretty',),
|
'classes': ('extrapretty',),
|
||||||
'fields': ('account_link', 'name', 'port', 'domains', 'is_active'),
|
'fields': ('account_link', 'name', 'protocol', 'domains', 'is_active'),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
form = WebsiteAdminForm
|
form = WebsiteAdminForm
|
||||||
|
@ -77,7 +77,7 @@ class WebsiteAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
def display_domains(self, website):
|
def display_domains(self, website):
|
||||||
domains = []
|
domains = []
|
||||||
for domain in website.domains.all():
|
for domain in website.domains.all():
|
||||||
url = '%s://%s' % (website.protocol, domain)
|
url = '%s://%s' % (website.get_protocol(), domain)
|
||||||
domains.append('<a href="%s">%s</a>' % (url, url))
|
domains.append('<a href="%s">%s</a>' % (url, url))
|
||||||
return '<br>'.join(domains)
|
return '<br>'.join(domains)
|
||||||
display_domains.short_description = _("domains")
|
display_domains.short_description = _("domains")
|
||||||
|
@ -102,9 +102,12 @@ class WebsiteAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
"""
|
"""
|
||||||
formfield = super(WebsiteAdmin, self).formfield_for_dbfield(db_field, **kwargs)
|
formfield = super(WebsiteAdmin, self).formfield_for_dbfield(db_field, **kwargs)
|
||||||
if db_field.name == 'domains':
|
if db_field.name == 'domains':
|
||||||
qset = Q()
|
qset = Q(
|
||||||
for port, __ in settings.WEBSITES_PORT_CHOICES:
|
Q(websites__protocol=Website.HTTPS_ONLY) |
|
||||||
qset = qset & Q(websites__port=port)
|
Q(websites__protocol=Website.HTTP_AND_HTTPS) | Q(
|
||||||
|
Q(websites__protocol=Website.HTTP) & Q(websites__protocol=Website.HTTPS)
|
||||||
|
)
|
||||||
|
)
|
||||||
args = resolve(kwargs['request'].path).args
|
args = resolve(kwargs['request'].path).args
|
||||||
if args:
|
if args:
|
||||||
object_id = args[0]
|
object_id = args[0]
|
||||||
|
|
|
@ -9,27 +9,31 @@ from orchestra.apps.orchestration import ServiceController
|
||||||
from orchestra.apps.resources import ServiceMonitor
|
from orchestra.apps.resources import ServiceMonitor
|
||||||
|
|
||||||
from .. import settings
|
from .. import settings
|
||||||
|
from ..utils import normurlpath
|
||||||
|
|
||||||
|
|
||||||
class Apache2Backend(ServiceController):
|
class Apache2Backend(ServiceController):
|
||||||
|
HTTP_PORT = 80
|
||||||
|
HTTPS_PORT = 443
|
||||||
|
|
||||||
model = 'websites.Website'
|
model = 'websites.Website'
|
||||||
related_models = (
|
related_models = (
|
||||||
('websites.Content', 'website'),
|
('websites.Content', 'website'),
|
||||||
)
|
)
|
||||||
verbose_name = _("Apache 2")
|
verbose_name = _("Apache 2")
|
||||||
|
|
||||||
def save(self, site):
|
def render_virtual_host(self, site, context, ssl=False):
|
||||||
context = self.get_context(site)
|
context['port'] = self.HTTPS_PORT if ssl else self.HTTP_PORT
|
||||||
extra_conf = self.get_content_directives(site)
|
extra_conf = self.get_content_directives(site)
|
||||||
if site.protocol is 'https':
|
directives = site.get_directives()
|
||||||
extra_conf += self.get_ssl(site)
|
if ssl:
|
||||||
extra_conf += self.get_security(site)
|
extra_conf += self.get_ssl(directives)
|
||||||
extra_conf += self.get_redirect(site)
|
extra_conf += self.get_security(directives)
|
||||||
|
extra_conf += self.get_redirects(directives)
|
||||||
|
extra_conf += self.get_proxies(directives)
|
||||||
context['extra_conf'] = extra_conf
|
context['extra_conf'] = extra_conf
|
||||||
|
return Template(textwrap.dedent("""\
|
||||||
apache_conf = Template(textwrap.dedent("""\
|
<VirtualHost {{ ip }}:{{ port }}>
|
||||||
# {{ banner }}
|
|
||||||
<VirtualHost {{ ip }}:{{ site.port }}>
|
|
||||||
ServerName {{ site.domains.all|first }}\
|
ServerName {{ site.domains.all|first }}\
|
||||||
{% if site.domains.all|slice:"1:" %}
|
{% if site.domains.all|slice:"1:" %}
|
||||||
ServerAlias {{ site.domains.all|slice:"1:"|join:' ' }}{% endif %}\
|
ServerAlias {{ site.domains.all|slice:"1:"|join:' ' }}{% endif %}\
|
||||||
|
@ -41,12 +45,38 @@ class Apache2Backend(ServiceController):
|
||||||
{% for line in extra_conf.splitlines %}
|
{% for line in extra_conf.splitlines %}
|
||||||
{{ line | safe }}{% endfor %}
|
{{ line | safe }}{% endfor %}
|
||||||
#IncludeOptional /etc/apache2/extra-vhos[t]/{{ site_unique_name }}.con[f]
|
#IncludeOptional /etc/apache2/extra-vhos[t]/{{ site_unique_name }}.con[f]
|
||||||
</VirtualHost>"""
|
</VirtualHost>
|
||||||
))
|
""")
|
||||||
apache_conf = apache_conf.render(Context(context))
|
).render(Context(context))
|
||||||
# apache_conf += self.get_protections(site)
|
|
||||||
context['apache_conf'] = apache_conf
|
|
||||||
|
|
||||||
|
def render_redirect_https(self, context):
|
||||||
|
context['port'] = self.HTTP_PORT
|
||||||
|
return Template(textwrap.dedent("""
|
||||||
|
<VirtualHost {{ ip }}:{{ port }}>
|
||||||
|
ServerName {{ site.domains.all|first }}\
|
||||||
|
{% if site.domains.all|slice:"1:" %}
|
||||||
|
ServerAlias {{ site.domains.all|slice:"1:"|join:' ' }}{% endif %}\
|
||||||
|
{% if access_log %}
|
||||||
|
CustomLog {{ access_log }} common{% endif %}\
|
||||||
|
{% if error_log %}
|
||||||
|
ErrorLog {{ error_log }}{% endif %}
|
||||||
|
RewriteEngine On
|
||||||
|
RewriteCond %{HTTPS} off
|
||||||
|
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
|
||||||
|
</VirtualHost>
|
||||||
|
""")
|
||||||
|
).render(Context(context))
|
||||||
|
|
||||||
|
def save(self, site):
|
||||||
|
context = self.get_context(site)
|
||||||
|
apache_conf = '# %(banner)s\n' % context
|
||||||
|
if site.protocol in (site.HTTP, site.HTTP_AND_HTTPS):
|
||||||
|
apache_conf += self.render_virtual_host(site, context, ssl=False)
|
||||||
|
if site.protocol in (site.HTTP_AND_HTTPS, site.HTTPS_ONLY, site.HTTPS):
|
||||||
|
apache_conf += self.render_virtual_host(site, context, ssl=True)
|
||||||
|
if site.protocol == site.HTTPS_ONLY:
|
||||||
|
apache_conf += self.render_redirect_https(context)
|
||||||
|
context['apache_conf'] = apache_conf
|
||||||
self.append(textwrap.dedent("""\
|
self.append(textwrap.dedent("""\
|
||||||
{
|
{
|
||||||
echo -e '%(apache_conf)s' | diff -N -I'^\s*#' %(sites_available)s -
|
echo -e '%(apache_conf)s' | diff -N -I'^\s*#' %(sites_available)s -
|
||||||
|
@ -78,7 +108,7 @@ class Apache2Backend(ServiceController):
|
||||||
def get_static_directives(self, content, app_path):
|
def get_static_directives(self, content, app_path):
|
||||||
context = self.get_content_context(content)
|
context = self.get_content_context(content)
|
||||||
context['app_path'] = app_path % context
|
context['app_path'] = app_path % context
|
||||||
return "Alias %(location)s %(app_path)s\n" % context
|
return "Alias %(location)s/ %(app_path)s/\n" % context
|
||||||
|
|
||||||
def get_fpm_directives(self, content, socket_type, socket, app_path):
|
def get_fpm_directives(self, content, socket_type, socket, app_path):
|
||||||
if socket_type == 'unix':
|
if socket_type == 'unix':
|
||||||
|
@ -95,8 +125,8 @@ class Apache2Backend(ServiceController):
|
||||||
'socket': socket,
|
'socket': socket,
|
||||||
})
|
})
|
||||||
return textwrap.dedent("""\
|
return textwrap.dedent("""\
|
||||||
ProxyPassMatch ^%(location)s(.*\.php(/.*)?)$ {target}
|
ProxyPassMatch ^%(location)s/(.*\.php(/.*)?)$ {target}
|
||||||
Alias %(location)s %(app_path)s/
|
Alias %(location)s/ %(app_path)s/
|
||||||
""".format(target=target) % context
|
""".format(target=target) % context
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -107,51 +137,60 @@ class Apache2Backend(ServiceController):
|
||||||
'wrapper_path': wrapper_path,
|
'wrapper_path': wrapper_path,
|
||||||
})
|
})
|
||||||
return textwrap.dedent("""\
|
return textwrap.dedent("""\
|
||||||
Alias %(location)s %(app_path)s
|
Alias %(location)s/ %(app_path)s/
|
||||||
ProxyPass %(location)s !
|
ProxyPass %(location)s/ !
|
||||||
<Directory %(app_path)s>
|
<Directory %(app_path)s/>
|
||||||
Options +ExecCGI
|
Options +ExecCGI
|
||||||
AddHandler fcgid-script .php
|
AddHandler fcgid-script .php
|
||||||
FcgidWrapper %(wrapper_path)s
|
FcgidWrapper %(wrapper_path)s
|
||||||
</Directory>
|
</Directory>
|
||||||
""") % context
|
""") % context
|
||||||
|
|
||||||
def get_ssl(self, site):
|
def get_ssl(self, directives):
|
||||||
cert = settings.WEBSITES_DEFAULT_HTTPS_CERT
|
config = []
|
||||||
custom_cert = site.options.filter(name='ssl')
|
ca = directives.get('ssl_ca')
|
||||||
if custom_cert:
|
if ca:
|
||||||
cert = tuple(custom_cert[0].value.split())
|
config.append("SSLCACertificateFile %s" % ca[0])
|
||||||
# TODO separate directtives?
|
cert = directives.get('ssl_cert')
|
||||||
directives = textwrap.dedent("""\
|
if cert:
|
||||||
SSLEngine on
|
config.append("SSLCertificateFile %" % cert[0])
|
||||||
SSLCertificateFile %s
|
key = directives.get('ssl_key')
|
||||||
SSLCertificateKeyFile %s\
|
if key:
|
||||||
""") % cert
|
config.append("SSLCertificateKeyFile %s" % key[0])
|
||||||
return directives
|
return '\n'.join(config)
|
||||||
|
|
||||||
def get_security(self, site):
|
def get_security(self, directives):
|
||||||
directives = ''
|
config = []
|
||||||
for rules in site.directives.filter(name='sec_rule_remove'):
|
for rules in directives.get('sec_rule_remove', []):
|
||||||
for rule in rules.value.split():
|
for rule in rules.value.split():
|
||||||
directives += "SecRuleRemoveById %i\n" % int(rule)
|
config.append("SecRuleRemoveById %i" % int(rule))
|
||||||
for modsecurity in site.directives.filter(name='sec_rule_off'):
|
for modsecurity in directives.get('sec_rule_off', []):
|
||||||
directives += textwrap.dedent("""\
|
config.append(textwrap.dedent("""\
|
||||||
<LocationMatch %s>
|
<Location %s>
|
||||||
SecRuleEngine Off
|
SecRuleEngine off
|
||||||
</LocationMatch>\
|
</LocationMatch>\
|
||||||
""") % modsecurity.value
|
""") % modsecurity
|
||||||
if directives:
|
)
|
||||||
directives = '<IfModule mod_security2.c>\n%s\n</IfModule>' % directives
|
return '\n'.join(config)
|
||||||
return directives
|
|
||||||
|
|
||||||
def get_redirect(self, site):
|
def get_redirects(self, directives):
|
||||||
directives = ''
|
config = []
|
||||||
for redirect in site.directives.filter(name='redirect'):
|
for redirect in directives.get('redirect', []):
|
||||||
if re.match(r'^.*[\^\*\$\?\)]+.*$', redirect.value):
|
source, target = redirect.split()
|
||||||
directives += "RedirectMatch %s" % redirect.value
|
if re.match(r'^.*[\^\*\$\?\)]+.*$', redirect):
|
||||||
|
config.append("RedirectMatch %s %s" % (source, target))
|
||||||
else:
|
else:
|
||||||
directives += "Redirect %s" % redirect.value
|
config.append("Redirect %s %s" % (source, target))
|
||||||
return directives
|
return '\n'.join(config)
|
||||||
|
|
||||||
|
def get_proxies(self, directives):
|
||||||
|
config = []
|
||||||
|
for proxy in directives.get('proxy', []):
|
||||||
|
source, target = redirect.split()
|
||||||
|
source = normurlpath(source)
|
||||||
|
config.append('ProxyPass %s %s' % (source, target))
|
||||||
|
config.append('ProxyPassReverse %s %s' % (source, target))
|
||||||
|
return '\n'.join(directives)
|
||||||
|
|
||||||
# def get_protections(self, site):
|
# def get_protections(self, site):
|
||||||
# protections = ''
|
# protections = ''
|
||||||
|
@ -192,15 +231,15 @@ class Apache2Backend(ServiceController):
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_username(self, site):
|
def get_username(self, site):
|
||||||
option = site.directives.filter(name='user_group').first()
|
option = site.get_directives().get('user_group')
|
||||||
if option:
|
if option:
|
||||||
return option.value.split()[0]
|
return option[0]
|
||||||
return site.account.username
|
return site.account.username
|
||||||
|
|
||||||
def get_groupname(self, site):
|
def get_groupname(self, site):
|
||||||
option = site.directives.filter(name='user_group').first()
|
option = site.get_directives().get('user_group')
|
||||||
if option and ' ' in option.value:
|
if option and ' ' in option:
|
||||||
user, group = option.value.split()
|
user, group = option.split()
|
||||||
return group
|
return group
|
||||||
return site.account.username
|
return site.account.username
|
||||||
|
|
||||||
|
@ -227,7 +266,7 @@ class Apache2Backend(ServiceController):
|
||||||
context = self.get_context(content.website)
|
context = self.get_context(content.website)
|
||||||
context.update({
|
context.update({
|
||||||
'type': content.webapp.type,
|
'type': content.webapp.type,
|
||||||
'location': content.path,
|
'location': normurlpath(content.path),
|
||||||
'app_name': content.webapp.name,
|
'app_name': content.webapp.name,
|
||||||
'app_path': content.webapp.get_path(),
|
'app_path': content.webapp.get_path(),
|
||||||
})
|
})
|
||||||
|
|
|
@ -9,7 +9,7 @@ from .. import settings
|
||||||
|
|
||||||
|
|
||||||
class WebalizerBackend(ServiceController):
|
class WebalizerBackend(ServiceController):
|
||||||
verbose_name = _("Webalizer")
|
verbose_name = _("Webalizer Content")
|
||||||
model = 'websites.Content'
|
model = 'websites.Content'
|
||||||
|
|
||||||
def save(self, content):
|
def save(self, content):
|
||||||
|
@ -27,7 +27,7 @@ class WebalizerBackend(ServiceController):
|
||||||
context = self.get_context(content)
|
context = self.get_context(content)
|
||||||
delete_webapp = type(content.webapp).objects.filter(pk=content.webapp.pk).exists()
|
delete_webapp = type(content.webapp).objects.filter(pk=content.webapp.pk).exists()
|
||||||
if delete_webapp:
|
if delete_webapp:
|
||||||
self.append("mv %(webapp_path)s %(webapp_path)s.deleted" % context)
|
self.append("rm -f %(webapp_path)s" % context)
|
||||||
if delete_webapp or not content.webapp.content_set.filter(website=content.website).exists():
|
if delete_webapp or not content.webapp.content_set.filter(website=content.website).exists():
|
||||||
self.append("rm -fr %(webalizer_path)s" % context)
|
self.append("rm -fr %(webalizer_path)s" % context)
|
||||||
self.append("rm -f %(webalizer_conf_path)s" % context)
|
self.append("rm -f %(webalizer_conf_path)s" % context)
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import re
|
||||||
|
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
@ -146,6 +148,6 @@ class SecRuleRemove(SiteDirective):
|
||||||
class SecEngine(SiteDirective):
|
class SecEngine(SiteDirective):
|
||||||
name = 'sec_engine'
|
name = 'sec_engine'
|
||||||
verbose_name = _("Modsecurity engine")
|
verbose_name = _("Modsecurity engine")
|
||||||
help_text = _("<tt>On</tt> or <tt>Off</tt>, defaults to On")
|
help_text = _("URL location for disabling modsecurity engine.")
|
||||||
regex = r'^(On|Off)$'
|
regex = r'^[^ ]+$'
|
||||||
group = SiteDirective.SEC
|
group = SiteDirective.SEC
|
||||||
|
|
|
@ -1,20 +1,43 @@
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
|
from django.db.models import Q
|
||||||
|
|
||||||
|
from .models import Website
|
||||||
|
|
||||||
|
|
||||||
class WebsiteAdminForm(forms.ModelForm):
|
class WebsiteAdminForm(forms.ModelForm):
|
||||||
def clean(self):
|
def clean(self):
|
||||||
""" Prevent multiples domains on the same port """
|
""" Prevent multiples domains on the same protocol """
|
||||||
domains = self.cleaned_data.get('domains')
|
domains = self.cleaned_data.get('domains')
|
||||||
port = self.cleaned_data.get('port')
|
if not domains:
|
||||||
|
return self.cleaned_data
|
||||||
|
protocol = self.cleaned_data.get('protocol')
|
||||||
existing = []
|
existing = []
|
||||||
for domain in domains.all():
|
for domain in domains.all():
|
||||||
if domain.websites.filter(port=port).exclude(pk=self.instance.pk).exists():
|
if protocol == Website.HTTP:
|
||||||
|
qset = Q(
|
||||||
|
Q(protocol=Website.HTTP) |
|
||||||
|
Q(protocol=Website.HTTP_AND_HTTPS) |
|
||||||
|
Q(protocol=Website.HTTPS_ONLY)
|
||||||
|
)
|
||||||
|
elif protocol == Website.HTTPS:
|
||||||
|
qset = Q(
|
||||||
|
Q(protocol=Website.HTTPS) |
|
||||||
|
Q(protocol=Website.HTTP_AND_HTTPS) |
|
||||||
|
Q(protocol=Website.HTTPS_ONLY)
|
||||||
|
)
|
||||||
|
elif protocol in (Website.HTTP_AND_HTTPS, Website.HTTPS_ONLY):
|
||||||
|
qset = Q()
|
||||||
|
else:
|
||||||
|
raise ValidationError({
|
||||||
|
'protocol': _("Unknown protocol %s") % protocol
|
||||||
|
})
|
||||||
|
if domain.websites.filter(qset).exclude(pk=self.instance.pk).exists():
|
||||||
existing.append(domain.name)
|
existing.append(domain.name)
|
||||||
if existing:
|
if existing:
|
||||||
context = (', '.join(existing), port)
|
context = (', '.join(existing), protocol)
|
||||||
raise ValidationError({
|
raise ValidationError({
|
||||||
'domains': 'A website is already defined for "%s" on port %s' % context
|
'domains': 'A website is already defined for "%s" on protocol %s' % context
|
||||||
})
|
})
|
||||||
return self.cleaned_data
|
return self.cleaned_data
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
|
@ -10,18 +11,26 @@ from orchestra.utils.functional import cached
|
||||||
|
|
||||||
from . import settings
|
from . import settings
|
||||||
from .directives import SiteDirective
|
from .directives import SiteDirective
|
||||||
|
from .utils import normurlpath
|
||||||
|
|
||||||
|
|
||||||
class Website(models.Model):
|
class Website(models.Model):
|
||||||
""" Models a web site, also known as virtual host """
|
""" Models a web site, also known as virtual host """
|
||||||
|
HTTP = 'http'
|
||||||
|
HTTPS = 'https'
|
||||||
|
HTTP_AND_HTTPS = 'http/https'
|
||||||
|
HTTPS_ONLY = 'https-only'
|
||||||
|
|
||||||
name = models.CharField(_("name"), max_length=128,
|
name = models.CharField(_("name"), max_length=128,
|
||||||
validators=[validators.validate_name])
|
validators=[validators.validate_name])
|
||||||
account = models.ForeignKey('accounts.Account', verbose_name=_("Account"),
|
account = models.ForeignKey('accounts.Account', verbose_name=_("Account"),
|
||||||
related_name='websites')
|
related_name='websites')
|
||||||
# TODO protocol
|
protocol = models.CharField(_("protocol"), max_length=16,
|
||||||
port = models.PositiveIntegerField(_("port"),
|
choices=settings.WEBSITES_PROTOCOL_CHOICES,
|
||||||
choices=settings.WEBSITES_PORT_CHOICES,
|
default=settings.WEBSITES_DEFAULT_PROTOCOL)
|
||||||
default=settings.WEBSITES_DEFAULT_PORT)
|
# port = models.PositiveIntegerField(_("port"),
|
||||||
|
# choices=settings.WEBSITES_PORT_CHOICES,
|
||||||
|
# default=settings.WEBSITES_DEFAULT_PORT)
|
||||||
domains = models.ManyToManyField(settings.WEBSITES_DOMAIN_MODEL,
|
domains = models.ManyToManyField(settings.WEBSITES_DOMAIN_MODEL,
|
||||||
related_name='websites', verbose_name=_("domains"))
|
related_name='websites', verbose_name=_("domains"))
|
||||||
contents = models.ManyToManyField('webapps.WebApp', through='websites.Content')
|
contents = models.ManyToManyField('webapps.WebApp', through='websites.Content')
|
||||||
|
@ -39,28 +48,29 @@ class Website(models.Model):
|
||||||
'id': self.id,
|
'id': self.id,
|
||||||
'pk': self.pk,
|
'pk': self.pk,
|
||||||
'account': self.account.username,
|
'account': self.account.username,
|
||||||
'port': self.port,
|
'protocol': self.protocol,
|
||||||
'name': self.name,
|
'name': self.name,
|
||||||
}
|
}
|
||||||
|
|
||||||
@property
|
def get_protocol(self):
|
||||||
def protocol(self):
|
if self.protocol in (self.HTTP, self.HTTP_AND_HTTPS):
|
||||||
if self.port == 80:
|
return self.HTTP
|
||||||
return 'http'
|
return self.HTTPS
|
||||||
if self.port == 443:
|
|
||||||
return 'https'
|
|
||||||
raise TypeError('No protocol for port "%s"' % self.port)
|
|
||||||
|
|
||||||
@cached
|
@cached
|
||||||
def get_directives(self):
|
def get_directives(self):
|
||||||
return {
|
directives = {}
|
||||||
opt.name: opt.value for opt in self.directives.all()
|
for opt in self.directives.all():
|
||||||
}
|
try:
|
||||||
|
directives[opt.name].append(opt.value)
|
||||||
|
except KeyError:
|
||||||
|
directives[opt.name] = [opt.value]
|
||||||
|
return directives
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
domain = self.domains.first()
|
domain = self.domains.first()
|
||||||
if domain:
|
if domain:
|
||||||
return '%s://%s' % (self.protocol, domain)
|
return '%s://%s' % (self.get_protocol(), domain)
|
||||||
|
|
||||||
def get_www_log_context(self):
|
def get_www_log_context(self):
|
||||||
return {
|
return {
|
||||||
|
@ -74,12 +84,12 @@ class Website(models.Model):
|
||||||
def get_www_access_log_path(self):
|
def get_www_access_log_path(self):
|
||||||
context = self.get_www_log_context()
|
context = self.get_www_log_context()
|
||||||
path = settings.WEBSITES_WEBSITE_WWW_ACCESS_LOG_PATH % context
|
path = settings.WEBSITES_WEBSITE_WWW_ACCESS_LOG_PATH % context
|
||||||
return path.replace('//', '/')
|
return os.path.normpath(path.replace('//', '/'))
|
||||||
|
|
||||||
def get_www_error_log_path(self):
|
def get_www_error_log_path(self):
|
||||||
context = self.get_www_log_context()
|
context = self.get_www_log_context()
|
||||||
path = settings.WEBSITES_WEBSITE_WWW_ERROR_LOG_PATH % context
|
path = settings.WEBSITES_WEBSITE_WWW_ERROR_LOG_PATH % context
|
||||||
return path.replace('//', '/')
|
return os.path.normpath(path.replace('//', '/'))
|
||||||
|
|
||||||
|
|
||||||
class Directive(models.Model):
|
class Directive(models.Model):
|
||||||
|
@ -122,15 +132,12 @@ class Content(models.Model):
|
||||||
return self.path
|
return self.path
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
if not self.path.startswith('/'):
|
self.path = normurlpath(self.path)
|
||||||
self.path = '/' + self.path
|
|
||||||
if not self.path.endswith('/'):
|
|
||||||
self.path = self.path + '/'
|
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
domain = self.website.domains.first()
|
domain = self.website.domains.first()
|
||||||
if domain:
|
if domain:
|
||||||
return '%s://%s%s' % (self.website.protocol, domain, self.path)
|
return '%s://%s%s' % (self.website.get_protocol(), domain, self.path)
|
||||||
|
|
||||||
|
|
||||||
services.register(Website)
|
services.register(Website)
|
||||||
|
|
|
@ -7,19 +7,21 @@ WEBSITES_UNIQUE_NAME_FORMAT = getattr(settings, 'WEBSITES_UNIQUE_NAME_FORMAT',
|
||||||
|
|
||||||
|
|
||||||
# TODO 'http', 'https', 'https-only', 'http and https' and rename to PROTOCOL
|
# TODO 'http', 'https', 'https-only', 'http and https' and rename to PROTOCOL
|
||||||
WEBSITES_PORT_CHOICES = getattr(settings, 'WEBSITES_PORT_CHOICES', (
|
#WEBSITES_PORT_CHOICES = getattr(settings, 'WEBSITES_PORT_CHOICES', (
|
||||||
(80, 'HTTP'),
|
# (80, 'HTTP'),
|
||||||
(443, 'HTTPS'),
|
# (443, 'HTTPS'),
|
||||||
))
|
#))
|
||||||
|
|
||||||
|
|
||||||
WEBSITES_PROTOCOL_CHOICES = getattr(settings, 'WEBSITES_PROTOCOL_CHOICES', (
|
WEBSITES_PROTOCOL_CHOICES = getattr(settings, 'WEBSITES_PROTOCOL_CHOICES', (
|
||||||
('http', "HTTP"),
|
('http', "HTTP"),
|
||||||
('https', "HTTPS"),
|
('https', "HTTPS"),
|
||||||
('http-https', _("HTTP and HTTPS")),
|
('http/https', _("HTTP and HTTPS")),
|
||||||
('https-only', _("HTTPS only")),
|
('https-only', _("HTTPS only")),
|
||||||
))
|
))
|
||||||
|
|
||||||
|
WEBSITES_DEFAULT_PROTOCOL = getattr(settings, 'WEBSITES_DEFAULT_PROTOCOL', 'http')
|
||||||
|
|
||||||
WEBSITES_DEFAULT_PORT = getattr(settings, 'WEBSITES_DEFAULT_PORT', 80)
|
WEBSITES_DEFAULT_PORT = getattr(settings, 'WEBSITES_DEFAULT_PORT', 80)
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,3 +62,13 @@ WEBSITES_WEBSITE_WWW_ERROR_LOG_PATH = getattr(settings, 'WEBSITES_WEBSITE_WWW_ER
|
||||||
|
|
||||||
WEBSITES_TRAFFIC_IGNORE_HOSTS = getattr(settings, 'WEBSITES_TRAFFIC_IGNORE_HOSTS',
|
WEBSITES_TRAFFIC_IGNORE_HOSTS = getattr(settings, 'WEBSITES_TRAFFIC_IGNORE_HOSTS',
|
||||||
('127.0.0.1',))
|
('127.0.0.1',))
|
||||||
|
|
||||||
|
|
||||||
|
#WEBSITES_DEFAULT_SSl_CA = getattr(settings, 'WEBSITES_DEFAULT_SSl_CA',
|
||||||
|
# '')
|
||||||
|
|
||||||
|
#WEBSITES_DEFAULT_SSl_CERT = getattr(settings, 'WEBSITES_DEFAULT_SSl_CERT',
|
||||||
|
# '')
|
||||||
|
|
||||||
|
#WEBSITES_DEFAULT_SSl_KEY = getattr(settings, 'WEBSITES_DEFAULT_SSl_KEY',
|
||||||
|
# '')
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
def normurlpath(path):
|
||||||
|
if not path.startswith('/'):
|
||||||
|
path = '/' + path
|
||||||
|
path = path.rstrip('/')
|
||||||
|
return path.replace('//', '/')
|
Loading…
Reference in New Issue