Fixes on webapps and websites backend execution
This commit is contained in:
parent
2a8d20910f
commit
44e8b29b43
4
TODO.md
4
TODO.md
|
@ -213,3 +213,7 @@ ssh-copy-id root@<server-address>
|
||||||
|
|
||||||
* webalizer backend on webapps and check webapps.websites.all()
|
* webalizer backend on webapps and check webapps.websites.all()
|
||||||
* monitor in batches doesnt work!!!
|
* monitor in batches doesnt work!!!
|
||||||
|
|
||||||
|
|
||||||
|
* mv: cannot move `/home/marcay/webapps/webalizer/' to a subdirectory of itself, `/home/marcay/webapps/webalizer/.deleted'
|
||||||
|
* Create utility for dealing with web paths '//', leading and ending '/'
|
||||||
|
|
|
@ -31,8 +31,8 @@ class MySQLBackend(ServiceController):
|
||||||
})
|
})
|
||||||
self.append(textwrap.dedent("""\
|
self.append(textwrap.dedent("""\
|
||||||
mysql -e 'GRANT ALL PRIVILEGES ON `%(database)s`.* TO "%(username)s"@"%(host)s" %(grant)s;' \
|
mysql -e 'GRANT ALL PRIVILEGES ON `%(database)s`.* TO "%(username)s"@"%(host)s" %(grant)s;' \
|
||||||
""" % context
|
""") % context
|
||||||
))
|
)
|
||||||
|
|
||||||
def delete(self, database):
|
def delete(self, database):
|
||||||
if database.type != database.MYSQL:
|
if database.type != database.MYSQL:
|
||||||
|
@ -62,12 +62,12 @@ class MySQLUserBackend(ServiceController):
|
||||||
context = self.get_context(user)
|
context = self.get_context(user)
|
||||||
self.append(textwrap.dedent("""\
|
self.append(textwrap.dedent("""\
|
||||||
mysql -e 'CREATE USER "%(username)s"@"%(host)s";' || true \
|
mysql -e 'CREATE USER "%(username)s"@"%(host)s";' || true \
|
||||||
""" % context
|
""") % context
|
||||||
))
|
)
|
||||||
self.append(textwrap.dedent("""\
|
self.append(textwrap.dedent("""\
|
||||||
mysql -e 'UPDATE mysql.user SET Password="%(password)s" WHERE User="%(username)s";' \
|
mysql -e 'UPDATE mysql.user SET Password="%(password)s" WHERE User="%(username)s";' \
|
||||||
""" % context
|
""") % context
|
||||||
))
|
)
|
||||||
|
|
||||||
def delete(self, user):
|
def delete(self, user):
|
||||||
if user.type != user.MYSQL:
|
if user.type != user.MYSQL:
|
||||||
|
@ -75,8 +75,8 @@ class MySQLUserBackend(ServiceController):
|
||||||
context = self.get_context(user)
|
context = self.get_context(user)
|
||||||
self.append(textwrap.dedent("""\
|
self.append(textwrap.dedent("""\
|
||||||
mysql -e 'DROP USER "%(username)s"@"%(host)s";' \
|
mysql -e 'DROP USER "%(username)s"@"%(host)s";' \
|
||||||
""" % context
|
""") % context
|
||||||
))
|
)
|
||||||
|
|
||||||
def commit(self):
|
def commit(self):
|
||||||
self.append("mysql -e 'FLUSH PRIVILEGES;'")
|
self.append("mysql -e 'FLUSH PRIVILEGES;'")
|
||||||
|
@ -99,8 +99,8 @@ class MysqlDisk(ServiceMonitor):
|
||||||
context = self.get_context(db)
|
context = self.get_context(db)
|
||||||
self.append(textwrap.dedent("""\
|
self.append(textwrap.dedent("""\
|
||||||
mysql -e 'UPDATE db SET Insert_priv="N", Create_priv="N" WHERE Db="%(db_name)s";'\
|
mysql -e 'UPDATE db SET Insert_priv="N", Create_priv="N" WHERE Db="%(db_name)s";'\
|
||||||
""" % context
|
""") % context
|
||||||
))
|
)
|
||||||
|
|
||||||
def recovery(self, db):
|
def recovery(self, db):
|
||||||
if db.type != db.MYSQL:
|
if db.type != db.MYSQL:
|
||||||
|
@ -108,8 +108,8 @@ class MysqlDisk(ServiceMonitor):
|
||||||
context = self.get_context(db)
|
context = self.get_context(db)
|
||||||
self.append(textwrap.dedent("""\
|
self.append(textwrap.dedent("""\
|
||||||
mysql -e 'UPDATE db SET Insert_priv="Y", Create_priv="Y" WHERE Db="%(db_name)s";'\
|
mysql -e 'UPDATE db SET Insert_priv="Y", Create_priv="Y" WHERE Db="%(db_name)s";'\
|
||||||
""" % context
|
""") % context
|
||||||
))
|
)
|
||||||
|
|
||||||
def prepare(self):
|
def prepare(self):
|
||||||
super(MysqlDisk, self).prepare()
|
super(MysqlDisk, self).prepare()
|
||||||
|
|
|
@ -36,8 +36,8 @@ class Bind9MasterDomainBackend(ServiceController):
|
||||||
mv %(zone_path)s.tmp %(zone_path)s
|
mv %(zone_path)s.tmp %(zone_path)s
|
||||||
# Because bind realod will not display any fucking error
|
# Because bind realod will not display any fucking error
|
||||||
named-checkzone -k fail -n fail %(name)s %(zone_path)s
|
named-checkzone -k fail -n fail %(name)s %(zone_path)s
|
||||||
""" % context
|
""") % context
|
||||||
))
|
)
|
||||||
self.update_conf(context)
|
self.update_conf(context)
|
||||||
|
|
||||||
def update_conf(self, context):
|
def update_conf(self, context):
|
||||||
|
@ -47,13 +47,13 @@ class Bind9MasterDomainBackend(ServiceController):
|
||||||
-e 'N; /^\s*\\n\s*$/d; P; D' %(conf_path)s
|
-e 'N; /^\s*\\n\s*$/d; P; D' %(conf_path)s
|
||||||
echo '%(conf)s' >> %(conf_path)s
|
echo '%(conf)s' >> %(conf_path)s
|
||||||
UPDATED=1
|
UPDATED=1
|
||||||
}""" % context
|
}""") % context
|
||||||
))
|
)
|
||||||
# Delete ex-top-domains that are now subdomains
|
# Delete ex-top-domains that are now subdomains
|
||||||
self.append(textwrap.dedent("""\
|
self.append(textwrap.dedent("""\
|
||||||
sed -i -e '/zone\s\s*".*\.%(name)s".*/,/^\s*};\s*$/d' \\
|
sed -i -e '/zone\s\s*".*\.%(name)s".*/,/^\s*};\s*$/d' \\
|
||||||
-e 'N; /^\s*\\n\s*$/d; P; D' %(conf_path)s""" % context
|
-e 'N; /^\s*\\n\s*$/d; P; D' %(conf_path)s""") % context
|
||||||
))
|
)
|
||||||
if 'zone_path' in context:
|
if 'zone_path' in context:
|
||||||
context['zone_subdomains_path'] = re.sub(r'^(.*/)', r'\1*.', context['zone_path'])
|
context['zone_subdomains_path'] = re.sub(r'^(.*/)', r'\1*.', context['zone_path'])
|
||||||
self.append('rm -f %(zone_subdomains_path)s' % context)
|
self.append('rm -f %(zone_subdomains_path)s' % context)
|
||||||
|
@ -69,19 +69,19 @@ class Bind9MasterDomainBackend(ServiceController):
|
||||||
return
|
return
|
||||||
self.append(textwrap.dedent("""\
|
self.append(textwrap.dedent("""\
|
||||||
sed -e '/zone\s\s*"%(name)s".*/,/^\s*};\s*$/d' \\
|
sed -e '/zone\s\s*"%(name)s".*/,/^\s*};\s*$/d' \\
|
||||||
-e 'N; /^\s*\\n\s*$/d; P; D' %(conf_path)s > %(conf_path)s.tmp""" % context
|
-e 'N; /^\s*\\n\s*$/d; P; D' %(conf_path)s > %(conf_path)s.tmp""") % context
|
||||||
))
|
)
|
||||||
self.append('diff -B -I"^\s*//" %(conf_path)s.tmp %(conf_path)s || UPDATED=1' % context)
|
self.append('diff -B -I"^\s*//" %(conf_path)s.tmp %(conf_path)s || UPDATED=1' % context)
|
||||||
self.append('mv %(conf_path)s.tmp %(conf_path)s' % context)
|
self.append('mv %(conf_path)s.tmp %(conf_path)s' % context)
|
||||||
|
|
||||||
def commit(self):
|
def commit(self):
|
||||||
""" reload bind if needed """
|
""" reload bind if needed """
|
||||||
self.append('[[ $UPDATED == 1 ]] && service bind9 reload')
|
self.append('if [[ $UPDATED == 1 ]]; then service bind9 reload; fi')
|
||||||
|
|
||||||
def get_servers(self, domain, backend):
|
def get_servers(self, domain, backend):
|
||||||
""" Get related server IPs from registered backend routes """
|
""" Get related server IPs from registered backend routes """
|
||||||
from orchestra.apps.orchestration.manager import router
|
from orchestra.apps.orchestration.manager import router
|
||||||
operation = Operation.create(backend, peration.SAVE, domain)
|
operation = Operation.create(backend, domain, Operation.SAVE)
|
||||||
servers = []
|
servers = []
|
||||||
for server in router.get_servers(operation):
|
for server in router.get_servers(operation):
|
||||||
servers.append(server.get_ip())
|
servers.append(server.get_ip())
|
||||||
|
@ -110,7 +110,7 @@ class Bind9MasterDomainBackend(ServiceController):
|
||||||
allow-transfer { %(slaves)s; };
|
allow-transfer { %(slaves)s; };
|
||||||
also-notify { %(also_notify)s };
|
also-notify { %(also_notify)s };
|
||||||
notify yes;
|
notify yes;
|
||||||
};""" % context)
|
};""") % context
|
||||||
})
|
})
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ class Bind9SlaveDomainBackend(Bind9MasterDomainBackend):
|
||||||
|
|
||||||
def commit(self):
|
def commit(self):
|
||||||
""" ideally slave should be restarted after master """
|
""" ideally slave should be restarted after master """
|
||||||
self.append('[[ $UPDATED == 1 ]] && { sleep 1 && service bind9 reload; } &')
|
self.append('if [[ $UPDATED == 1 ]]; then { sleep 1 && service bind9 reload; } & fi')
|
||||||
|
|
||||||
def get_masters(self, domain):
|
def get_masters(self, domain):
|
||||||
return self.get_servers(domain, Bind9MasterDomainBackend)
|
return self.get_servers(domain, Bind9MasterDomainBackend)
|
||||||
|
@ -152,6 +152,6 @@ class Bind9SlaveDomainBackend(Bind9MasterDomainBackend):
|
||||||
file "%(name)s";
|
file "%(name)s";
|
||||||
masters { %(masters)s; };
|
masters { %(masters)s; };
|
||||||
allow-notify { %(masters)s; };
|
allow-notify { %(masters)s; };
|
||||||
};""" % context)
|
};""") % context
|
||||||
})
|
})
|
||||||
return context
|
return context
|
||||||
|
|
|
@ -33,8 +33,8 @@ class PasswdVirtualUserBackend(ServiceController):
|
||||||
sed -i 's#^%(username)s:.*#%(passwd)s#' %(passwd_path)s
|
sed -i 's#^%(username)s:.*#%(passwd)s#' %(passwd_path)s
|
||||||
else
|
else
|
||||||
echo '%(passwd)s' >> %(passwd_path)s
|
echo '%(passwd)s' >> %(passwd_path)s
|
||||||
fi""" % context
|
fi""") % context
|
||||||
))
|
)
|
||||||
self.append("mkdir -p %(home)s" % context)
|
self.append("mkdir -p %(home)s" % context)
|
||||||
self.append("chown %(uid)s:%(gid)s %(home)s" % context)
|
self.append("chown %(uid)s:%(gid)s %(home)s" % context)
|
||||||
|
|
||||||
|
@ -43,7 +43,8 @@ class PasswdVirtualUserBackend(ServiceController):
|
||||||
if [[ ! $(grep "^%(username)s@%(mailbox_domain)s\s" %(virtual_mailbox_maps)s) ]]; then
|
if [[ ! $(grep "^%(username)s@%(mailbox_domain)s\s" %(virtual_mailbox_maps)s) ]]; then
|
||||||
echo "%(username)s@%(mailbox_domain)s\tOK" >> %(virtual_mailbox_maps)s
|
echo "%(username)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 %(username)s Spam" % context)
|
||||||
|
@ -92,7 +93,8 @@ class PasswdVirtualUserBackend(ServiceController):
|
||||||
self.append(textwrap.dedent("""\
|
self.append(textwrap.dedent("""\
|
||||||
[[ $UPDATED_VIRTUAL_MAILBOX_MAPS == 1 ]] && {
|
[[ $UPDATED_VIRTUAL_MAILBOX_MAPS == 1 ]] && {
|
||||||
postmap %(virtual_mailbox_maps)s
|
postmap %(virtual_mailbox_maps)s
|
||||||
}""" % context))
|
}""") % context
|
||||||
|
)
|
||||||
|
|
||||||
def get_context(self, mailbox):
|
def get_context(self, mailbox):
|
||||||
context = {
|
context = {
|
||||||
|
|
|
@ -154,7 +154,7 @@ class BackendOperation(models.Model):
|
||||||
"""
|
"""
|
||||||
if self.action == self.DELETE:
|
if self.action == self.DELETE:
|
||||||
if hasattr(self.backend, 'get_context'):
|
if hasattr(self.backend, 'get_context'):
|
||||||
self.backend.get_context(self.instance)
|
self.backend().get_context(self.instance)
|
||||||
|
|
||||||
def backend_class(self):
|
def backend_class(self):
|
||||||
return ServiceBackend.get_backend(self.backend)
|
return ServiceBackend.get_backend(self.backend)
|
||||||
|
|
|
@ -26,8 +26,8 @@ class SystemUserBackend(ServiceController):
|
||||||
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 %(username)s:%(username)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 %(username)s %(member)s' % context)
|
||||||
|
@ -40,8 +40,8 @@ class SystemUserBackend(ServiceController):
|
||||||
{ sleep 2 && killall -u %(username)s -s KILL; } &
|
{ sleep 2 && killall -u %(username)s -s KILL; } &
|
||||||
killall -u %(username)s || true
|
killall -u %(username)s || true
|
||||||
userdel %(username)s || true
|
userdel %(username)s || true
|
||||||
groupdel %(username)s || true""" % context
|
groupdel %(username)s || true""") % context
|
||||||
))
|
)
|
||||||
self.delete_home(context, user)
|
self.delete_home(context, user)
|
||||||
|
|
||||||
def grant_permission(self, user):
|
def grant_permission(self, user):
|
||||||
|
@ -145,7 +145,7 @@ class FTPTraffic(ServiceMonitor):
|
||||||
print sum
|
print sum
|
||||||
}' || [[ $? == 1 ]] && true
|
}' || [[ $? == 1 ]] && true
|
||||||
} | xargs echo ${OBJECT_ID}
|
} | xargs echo ${OBJECT_ID}
|
||||||
}""" % current_date))
|
}""") % current_date)
|
||||||
|
|
||||||
def monitor(self, user):
|
def monitor(self, user):
|
||||||
context = self.get_context(user)
|
context = self.get_context(user)
|
||||||
|
|
|
@ -53,7 +53,7 @@ class WebAppAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin)
|
||||||
inlines = [WebAppOptionInline]
|
inlines = [WebAppOptionInline]
|
||||||
readonly_fields = ('account_link',)
|
readonly_fields = ('account_link',)
|
||||||
change_readonly_fields = ('name', 'type')
|
change_readonly_fields = ('name', 'type')
|
||||||
list_prefetch_related = ('contents__website',)
|
list_prefetch_related = ('content_set__website',)
|
||||||
plugin = AppType
|
plugin = AppType
|
||||||
plugin_field = 'type'
|
plugin_field = 'type'
|
||||||
plugin_title = _("Web application type")
|
plugin_title = _("Web application type")
|
||||||
|
@ -64,7 +64,7 @@ class WebAppAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin)
|
||||||
|
|
||||||
def display_websites(self, webapp):
|
def display_websites(self, webapp):
|
||||||
websites = []
|
websites = []
|
||||||
for content in webapp.contents.all():
|
for content in webapp.content_set.all():
|
||||||
website = content.website
|
website = content.website
|
||||||
url = change_url(website)
|
url = change_url(website)
|
||||||
name = "%s on %s" % (website.name, content.path)
|
name = "%s on %s" % (website.name, content.path)
|
||||||
|
|
|
@ -1,15 +1,22 @@
|
||||||
import pkgutil
|
import pkgutil
|
||||||
import textwrap
|
import textwrap
|
||||||
|
|
||||||
|
from .. import settings
|
||||||
|
|
||||||
|
|
||||||
class WebAppServiceMixin(object):
|
class WebAppServiceMixin(object):
|
||||||
model = 'webapps.WebApp'
|
model = 'webapps.WebApp'
|
||||||
directive = None
|
directive = None
|
||||||
|
|
||||||
def create_webapp_dir(self, context):
|
def create_webapp_dir(self, context):
|
||||||
|
self.append("[[ ! -e %(app_path)s ]] && CREATED=true" % context)
|
||||||
self.append("mkdir -p %(app_path)s" % context)
|
self.append("mkdir -p %(app_path)s" % context)
|
||||||
self.append("chown %(user)s:%(group)s %(app_path)s" % context)
|
self.append("chown %(user)s:%(group)s %(app_path)s" % context)
|
||||||
|
|
||||||
|
def set_under_construction(self, context):
|
||||||
|
if context['under_construction_path']:
|
||||||
|
self.append("[[ $CREATED ]] && cp -r %(under_construction_path)s %(app_path)s" % context)
|
||||||
|
|
||||||
def delete_webapp_dir(self, context):
|
def delete_webapp_dir(self, context):
|
||||||
self.append("rm -fr %(app_path)s" % context)
|
self.append("rm -fr %(app_path)s" % context)
|
||||||
|
|
||||||
|
@ -21,6 +28,7 @@ class WebAppServiceMixin(object):
|
||||||
'type': webapp.type,
|
'type': webapp.type,
|
||||||
'app_path': webapp.get_path().rstrip('/'),
|
'app_path': webapp.get_path().rstrip('/'),
|
||||||
'banner': self.get_banner(),
|
'banner': self.get_banner(),
|
||||||
|
'under_construction_path': settings.settings.WEBAPPS_UNDER_CONSTRUCTION_PATH
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -12,54 +12,82 @@ from .. import settings
|
||||||
class PHPFcgidBackend(WebAppServiceMixin, ServiceController):
|
class PHPFcgidBackend(WebAppServiceMixin, ServiceController):
|
||||||
""" Per-webapp fcgid application """
|
""" Per-webapp fcgid application """
|
||||||
verbose_name = _("PHP-Fcgid")
|
verbose_name = _("PHP-Fcgid")
|
||||||
directive = 'fcgi'
|
directive = 'fcgid'
|
||||||
default_route_match = "webapp.type.endswith('-fcgi')"
|
default_route_match = "webapp.type.endswith('-fcgid')"
|
||||||
|
|
||||||
def save(self, webapp):
|
def save(self, webapp):
|
||||||
if not self.valid_directive(webapp):
|
|
||||||
return
|
|
||||||
context = self.get_context(webapp)
|
context = self.get_context(webapp)
|
||||||
self.create_webapp_dir(context)
|
self.create_webapp_dir(context)
|
||||||
|
self.set_under_construction(context)
|
||||||
self.append("mkdir -p %(wrapper_dir)s" % context)
|
self.append("mkdir -p %(wrapper_dir)s" % context)
|
||||||
self.append(textwrap.dedent("""\
|
self.append(textwrap.dedent("""\
|
||||||
{
|
{
|
||||||
echo -e '%(wrapper_content)s' | diff -N -I'^\s*#' %(wrapper_path)s -
|
echo -e '%(wrapper)s' | diff -N -I'^\s*#' %(wrapper_path)s -
|
||||||
} || {
|
} || {
|
||||||
echo -e '%(wrapper_content)s' > %(wrapper_path)s; UPDATED_APACHE=1
|
echo -e '%(wrapper)s' > %(wrapper_path)s; UPDATED_APACHE=1
|
||||||
}""" % context))
|
}""") % context
|
||||||
|
)
|
||||||
self.append("chmod +x %(wrapper_path)s" % context)
|
self.append("chmod +x %(wrapper_path)s" % context)
|
||||||
self.append("chown -R %(user)s:%(group)s %(wrapper_dir)s" % context)
|
self.append("chown -R %(user)s:%(group)s %(wrapper_dir)s" % context)
|
||||||
|
if context['cmd_options']:
|
||||||
|
self.append(textwrap.dedent("""
|
||||||
|
{
|
||||||
|
echo -e '%(cmd_options)s' | diff -N -I'^\s*#' %(cmd_options_path)s -
|
||||||
|
} || {
|
||||||
|
echo -e '%(cmd_options)s' > %(cmd_options_path)s; UPDATED_APACHE=1
|
||||||
|
}""" ) % context
|
||||||
|
)
|
||||||
|
|
||||||
def delete(self, webapp):
|
def delete(self, webapp):
|
||||||
if not self.valid_directive(webapp):
|
|
||||||
return
|
|
||||||
context = self.get_context(webapp)
|
context = self.get_context(webapp)
|
||||||
self.append("rm '%(wrapper_path)s'" % context)
|
self.append("rm '%(wrapper_path)s'" % context)
|
||||||
self.delete_webapp_dir(context)
|
self.delete_webapp_dir(context)
|
||||||
|
|
||||||
def commit(self):
|
def commit(self):
|
||||||
if not self.cmds:
|
self.append('if [[ $UPDATED_APACHE == 1 ]]; then service apache2 reload; fi')
|
||||||
return
|
|
||||||
super(PHPFcgidBackend, self).commit()
|
def get_fcgid_wrapper(self, webapp, context):
|
||||||
self.append("[[ $UPDATED_APACHE == 1 ]] && { service apache2 reload; }")
|
opt = webapp.type_instance
|
||||||
|
# Format PHP init vars
|
||||||
|
init_vars = opt.get_php_init_vars(webapp)
|
||||||
|
if init_vars:
|
||||||
|
init_vars = [ '-d %s="%s"' % (k,v) for k,v in init_vars.iteritems() ]
|
||||||
|
init_vars = ', '.join(init_vars)
|
||||||
|
|
||||||
|
context.update({
|
||||||
|
'php_binary': opt.php_binary,
|
||||||
|
'php_rc': opt.php_rc,
|
||||||
|
'php_init_vars': init_vars,
|
||||||
|
})
|
||||||
|
return textwrap.dedent("""\
|
||||||
|
#!/bin/sh
|
||||||
|
# %(banner)s
|
||||||
|
export PHPRC=%(php_rc)s
|
||||||
|
exec %(php_binary)s %(php_init_vars)s""") % context
|
||||||
|
|
||||||
|
def get_fcgid_cmd_options(self, webapp, context):
|
||||||
|
maps = {
|
||||||
|
'MaxProcesses': webapp.get_options().get('processes', None),
|
||||||
|
'IOTimeout': webapp.get_options().get('timeout', None),
|
||||||
|
}
|
||||||
|
cmd_options = []
|
||||||
|
for directive, value in maps.iteritems():
|
||||||
|
if value:
|
||||||
|
cmd_options.append("%s %s" % (directive, value))
|
||||||
|
if cmd_options:
|
||||||
|
cmd_options.insert(0, 'FcgidCmdOptions %(wrapper_path)s' % context)
|
||||||
|
return ' \\\n '.join(cmd_options)
|
||||||
|
|
||||||
def get_context(self, webapp):
|
def get_context(self, webapp):
|
||||||
context = super(PHPFcgidBackend, self).get_context(webapp)
|
context = super(PHPFcgidBackend, self).get_context(webapp)
|
||||||
init_vars = self.get_php_init_vars(webapp)
|
|
||||||
if init_vars:
|
|
||||||
init_vars = [ '%s="%s"' % (k,v) for k,v in init_vars ]
|
|
||||||
init_vars = ', -d '.join(init_vars)
|
|
||||||
context['init_vars'] = '-d %s' % init_vars
|
|
||||||
else:
|
|
||||||
context['init_vars'] = ''
|
|
||||||
wrapper_path = settings.WEBAPPS_FCGID_PATH % context
|
wrapper_path = settings.WEBAPPS_FCGID_PATH % context
|
||||||
context.update({
|
context.update({
|
||||||
'wrapper_content': textwrap.dedent("""\
|
'wrapper': self.get_fcgid_wrapper(webapp, context),
|
||||||
#!/bin/sh
|
|
||||||
# %(banner)s
|
|
||||||
export PHPRC=/etc/%(type)s/cgi/
|
|
||||||
exec /usr/bin/%(type)s-cgi %(init_vars)s""" % context),
|
|
||||||
'wrapper_path': wrapper_path,
|
'wrapper_path': wrapper_path,
|
||||||
'wrapper_dir': os.path.dirname(wrapper_path),
|
'wrapper_dir': os.path.dirname(wrapper_path),
|
||||||
})
|
})
|
||||||
|
context.update({
|
||||||
|
'cmd_options': self.get_fcgid_cmd_options(webapp, context),
|
||||||
|
'cmd_options_path': settings.WEBAPPS_FCGID_CMD_OPTIONS_PATH % context,
|
||||||
|
})
|
||||||
return context
|
return context
|
||||||
|
|
|
@ -18,14 +18,15 @@ class PHPFPMBackend(WebAppServiceMixin, ServiceController):
|
||||||
def save(self, webapp):
|
def save(self, webapp):
|
||||||
context = self.get_context(webapp)
|
context = self.get_context(webapp)
|
||||||
self.create_webapp_dir(context)
|
self.create_webapp_dir(context)
|
||||||
|
self.set_under_construction(context)
|
||||||
self.append(textwrap.dedent("""\
|
self.append(textwrap.dedent("""\
|
||||||
{
|
{
|
||||||
echo -e '%(fpm_config)s' | diff -N -I'^\s*;;' %(fpm_path)s -
|
echo -e '%(fpm_config)s' | diff -N -I'^\s*;;' %(fpm_path)s -
|
||||||
} || {
|
} || {
|
||||||
echo -e '%(fpm_config)s' > %(fpm_path)s
|
echo -e '%(fpm_config)s' > %(fpm_path)s
|
||||||
UPDATEDFPM=1
|
UPDATEDFPM=1
|
||||||
}""" % context
|
}""") % context
|
||||||
))
|
)
|
||||||
|
|
||||||
def delete(self, webapp):
|
def delete(self, webapp):
|
||||||
context = self.get_context(webapp)
|
context = self.get_context(webapp)
|
||||||
|
@ -37,18 +38,17 @@ class PHPFPMBackend(WebAppServiceMixin, ServiceController):
|
||||||
return
|
return
|
||||||
super(PHPFPMBackend, self).commit()
|
super(PHPFPMBackend, self).commit()
|
||||||
self.append(textwrap.dedent("""
|
self.append(textwrap.dedent("""
|
||||||
[[ $UPDATEDFPM == 1 ]] && {
|
if [[ $UPDATEDFPM == 1 ]]; then
|
||||||
service php5-fpm reload
|
service php5-fpm reload
|
||||||
service php5-fpm start
|
service php5-fpm start
|
||||||
}"""))
|
fi"""))
|
||||||
|
|
||||||
def get_context(self, webapp):
|
def get_fpm_config(self, webapp, context):
|
||||||
if not self.valid_directive(webapp):
|
|
||||||
return
|
|
||||||
context = super(PHPFPMBackend, self).get_context(webapp)
|
|
||||||
context.update({
|
context.update({
|
||||||
'init_vars': self.get_php_init_vars(webapp),
|
'init_vars': webapp.type_instance.get_php_init_vars(webapp),
|
||||||
'fpm_port': webapp.get_fpm_port(),
|
'fpm_port': webapp.get_fpm_port(),
|
||||||
|
'max_children': webapp.get_options().get('processes', False),
|
||||||
|
'request_terminate_timeout': webapp.get_options().get('timeout', False),
|
||||||
})
|
})
|
||||||
context['fpm_listen'] = settings.WEBAPPS_FPM_LISTEN % context
|
context['fpm_listen'] = settings.WEBAPPS_FPM_LISTEN % context
|
||||||
fpm_config = Template(textwrap.dedent("""\
|
fpm_config = Template(textwrap.dedent("""\
|
||||||
|
@ -61,12 +61,18 @@ class PHPFPMBackend(WebAppServiceMixin, ServiceController):
|
||||||
listen.owner = {{ user }}
|
listen.owner = {{ user }}
|
||||||
listen.group = {{ group }}
|
listen.group = {{ group }}
|
||||||
pm = ondemand
|
pm = ondemand
|
||||||
pm.max_children = 4
|
{% if max_children %}pm.max_children = {{ max_children }}{% endif %}
|
||||||
{% for name, value in init_vars %}
|
{% if request_terminate_timeout %}request_terminate_timeout = {{ request_terminate_timeout }}{% endif %}
|
||||||
php_admin_value[{{ name | safe }}] = {{ value | safe }}{% endfor %}"""
|
{% for name, value in init_vars.iteritems %}
|
||||||
|
php_admin_value[{{ name | safe }}] = {{ value | safe }}{% endfor %}
|
||||||
|
"""
|
||||||
))
|
))
|
||||||
|
return fpm_config.render(Context(context))
|
||||||
|
|
||||||
|
def get_context(self, webapp):
|
||||||
|
context = super(PHPFPMBackend, self).get_context(webapp)
|
||||||
context.update({
|
context.update({
|
||||||
'fpm_config': fpm_config.render(Context(context)),
|
'fpm_config': self.get_fpm_config(webapp, context),
|
||||||
'fpm_path': settings.WEBAPPS_PHPFPM_POOL_PATH % context,
|
'fpm_path': settings.WEBAPPS_PHPFPM_POOL_PATH % context,
|
||||||
})
|
})
|
||||||
return context
|
return context
|
||||||
|
|
|
@ -7,17 +7,13 @@ from . import WebAppServiceMixin
|
||||||
|
|
||||||
class StaticBackend(WebAppServiceMixin, ServiceController):
|
class StaticBackend(WebAppServiceMixin, ServiceController):
|
||||||
verbose_name = _("Static")
|
verbose_name = _("Static")
|
||||||
directive = 'static'
|
|
||||||
default_route_match = "webapp.type == 'static'"
|
default_route_match = "webapp.type == 'static'"
|
||||||
|
|
||||||
def save(self, webapp):
|
def save(self, webapp):
|
||||||
if not self.valid_directive(webapp):
|
|
||||||
return
|
|
||||||
context = self.get_context(webapp)
|
context = self.get_context(webapp)
|
||||||
self.create_webapp_dir(context)
|
self.create_webapp_dir(context)
|
||||||
|
self.set_under_construction(context)
|
||||||
|
|
||||||
def delete(self, webapp):
|
def delete(self, webapp):
|
||||||
if not self.valid_directive(webapp):
|
|
||||||
return
|
|
||||||
context = self.get_context(webapp)
|
context = self.get_context(webapp)
|
||||||
self.delete_webapp_dir(context)
|
self.delete_webapp_dir(context)
|
||||||
|
|
|
@ -30,8 +30,8 @@ class WordPressBackend(WebAppServiceMixin, ServiceController):
|
||||||
mkdir %(app_path)s/wp-content/uploads
|
mkdir %(app_path)s/wp-content/uploads
|
||||||
chmod 750 %(app_path)s/wp-content/uploads
|
chmod 750 %(app_path)s/wp-content/uploads
|
||||||
chown -R %(user)s:%(group)s %(app_path)s
|
chown -R %(user)s:%(group)s %(app_path)s
|
||||||
fi""" % context
|
fi""") % context
|
||||||
))
|
)
|
||||||
|
|
||||||
def delete(self, webapp):
|
def delete(self, webapp):
|
||||||
context = self.get_context(webapp)
|
context = self.get_context(webapp)
|
||||||
|
|
|
@ -12,6 +12,7 @@ from orchestra.core import validators, services
|
||||||
from orchestra.utils.functional import cached
|
from orchestra.utils.functional import cached
|
||||||
|
|
||||||
from . import settings
|
from . import settings
|
||||||
|
from .options import AppOption
|
||||||
from .types import AppType
|
from .types import AppType
|
||||||
|
|
||||||
|
|
||||||
|
@ -55,9 +56,6 @@ class WebApp(models.Model):
|
||||||
opt.name: opt.value for opt in self.options.all()
|
opt.name: opt.value for opt in self.options.all()
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_fpm_port(self):
|
|
||||||
return settings.WEBAPPS_FPM_START_PORT + self.account_id
|
|
||||||
|
|
||||||
def get_directive(self):
|
def get_directive(self):
|
||||||
return self.type_instance.get_directive(self)
|
return self.type_instance.get_directive(self)
|
||||||
|
|
||||||
|
@ -67,6 +65,9 @@ class WebApp(models.Model):
|
||||||
'app_name': self.name,
|
'app_name': self.name,
|
||||||
}
|
}
|
||||||
path = settings.WEBAPPS_BASE_ROOT % context
|
path = settings.WEBAPPS_BASE_ROOT % context
|
||||||
|
public_root = self.options.filter(name='public-root').first()
|
||||||
|
if public_root:
|
||||||
|
path = os.path.join(path, public_root.value)
|
||||||
return path.replace('//', '/')
|
return path.replace('//', '/')
|
||||||
|
|
||||||
def get_user(self):
|
def get_user(self):
|
||||||
|
@ -95,7 +96,7 @@ class WebAppOption(models.Model):
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def option_class(self):
|
def option_class(self):
|
||||||
return SiteDirective.get_plugin(self.name)
|
return AppOption.get_plugin(self.name)
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def option_instance(self):
|
def option_instance(self):
|
||||||
|
|
|
@ -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 _
|
||||||
|
|
||||||
|
@ -54,15 +56,6 @@ class PublicRoot(AppOption):
|
||||||
group = AppOption.FILESYSTEM
|
group = AppOption.FILESYSTEM
|
||||||
|
|
||||||
|
|
||||||
class DirectoryProtection(AppOption):
|
|
||||||
name = 'directory-protection'
|
|
||||||
verbose_name = _("Directory protection")
|
|
||||||
help_text = _("Space separated ...")
|
|
||||||
regex = r'^([\w/_]+)\s+(\".*\")\s+([\w/_\.]+)$'
|
|
||||||
group = AppOption.FILESYSTEM
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Timeout(AppOption):
|
class Timeout(AppOption):
|
||||||
name = 'timeout'
|
name = 'timeout'
|
||||||
# FCGID FcgidIOTimeout
|
# FCGID FcgidIOTimeout
|
||||||
|
@ -271,7 +264,7 @@ class PHPSessionBugCompatWarn(AppOption):
|
||||||
|
|
||||||
|
|
||||||
class PHPSessionAutoStart(AppOption):
|
class PHPSessionAutoStart(AppOption):
|
||||||
name = 'session.auto_start',
|
name = 'session.auto_start'
|
||||||
verbose_name = _("session.auto_start")
|
verbose_name = _("session.auto_start")
|
||||||
help_text = _("Specifies whether the session module starts a session automatically on request "
|
help_text = _("Specifies whether the session module starts a session automatically on request "
|
||||||
"startup (On or Off).")
|
"startup (On or Off).")
|
||||||
|
@ -289,7 +282,7 @@ class PHPSafeMode(AppOption):
|
||||||
|
|
||||||
|
|
||||||
class PHPSuhosinPostMaxVars(AppOption):
|
class PHPSuhosinPostMaxVars(AppOption):
|
||||||
name = 'suhosin.post.max_vars',
|
name = 'suhosin.post.max_vars'
|
||||||
verbose_name = _("Suhosin POST max vars")
|
verbose_name = _("Suhosin POST max vars")
|
||||||
help_text = _("Number between 0 and 9999.")
|
help_text = _("Number between 0 and 9999.")
|
||||||
regex = r'^[0-9]{1,4}$'
|
regex = r'^[0-9]{1,4}$'
|
||||||
|
@ -336,7 +329,7 @@ class PHPSuhosinExecutorIncludeWhitelist(AppOption):
|
||||||
|
|
||||||
|
|
||||||
class PHPUploadMaxFileSize(AppOption):
|
class PHPUploadMaxFileSize(AppOption):
|
||||||
name = 'upload_max_filesize',
|
name = 'upload_max_filesize'
|
||||||
verbose_name = _("upload_max_filesize")
|
verbose_name = _("upload_max_filesize")
|
||||||
help_text = _("Value between 0M and 999M.")
|
help_text = _("Value between 0M and 999M.")
|
||||||
regex = r'^[0-9]{1,3}M$'
|
regex = r'^[0-9]{1,3}M$'
|
||||||
|
|
|
@ -2,28 +2,31 @@ from django.conf import settings
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
WEBAPPS_BASE_ROOT = getattr(settings, 'WEBAPPS_BASE_ROOT', '{home}/webapps/{app_name}/')
|
WEBAPPS_BASE_ROOT = getattr(settings, 'WEBAPPS_BASE_ROOT', '%(home)s/webapps/%(app_name)s/')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
WEBAPPS_FPM_LISTEN = getattr(settings, 'WEBAPPS_FPM_LISTEN',
|
WEBAPPS_FPM_LISTEN = getattr(settings, 'WEBAPPS_FPM_LISTEN',
|
||||||
# '127.0.0.1:9{app_id:03d}
|
# '127.0.0.1:9%(app_id)03d
|
||||||
'/opt/php/5.4/socks/{user}-{app_name}.sock'
|
'/opt/php/5.4/socks/%(user)s-%(app_name)s.sock'
|
||||||
)
|
)
|
||||||
|
|
||||||
WEBAPPS_FPM_START_PORT = getattr(settings, 'WEBAPPS_FPM_START_PORT', 10000)
|
|
||||||
|
|
||||||
|
|
||||||
WEBAPPS_PHPFPM_POOL_PATH = getattr(settings, 'WEBAPPS_PHPFPM_POOL_PATH',
|
WEBAPPS_PHPFPM_POOL_PATH = getattr(settings, 'WEBAPPS_PHPFPM_POOL_PATH',
|
||||||
'/etc/php5/fpm/pool.d/{user}-{app_name}.conf')
|
'/etc/php5/fpm/pool.d/%(user)s-%(app_name)s.conf')
|
||||||
|
|
||||||
|
|
||||||
WEBAPPS_FCGID_PATH = getattr(settings, 'WEBAPPS_FCGID_PATH',
|
WEBAPPS_FCGID_PATH = getattr(settings, 'WEBAPPS_FCGID_PATH',
|
||||||
'/home/httpd/fcgid/{user}/{app_name}-wrapper')
|
'/home/httpd/fcgi-bin.d/%(user)s/%(app_name)s-wrapper')
|
||||||
|
|
||||||
|
|
||||||
|
WEBAPPS_FCGID_CMD_OPTIONS_PATH = getattr(settings, 'WEBAPPS_FCGID_CMD_OPTIONS_PATH',
|
||||||
|
'/etc/apache2/fcgid-conf/%(user)s-%(app_name)s.conf')
|
||||||
|
|
||||||
|
|
||||||
|
WEBAPPS_PHP_ERROR_LOG_PATH = getattr(settings, 'WEBAPPS_PHP_ERROR_LOG_PATH',
|
||||||
|
'')
|
||||||
|
|
||||||
WEBAPPS_TYPES = getattr(settings, 'WEBAPPS_TYPES', (
|
WEBAPPS_TYPES = getattr(settings, 'WEBAPPS_TYPES', (
|
||||||
'orchestra.apps.webapps.types.PHP54App',
|
'orchestra.apps.webapps.types.PHP54App',
|
||||||
|
'orchestra.apps.webapps.types.PHP53App',
|
||||||
'orchestra.apps.webapps.types.PHP52App',
|
'orchestra.apps.webapps.types.PHP52App',
|
||||||
'orchestra.apps.webapps.types.PHP4App',
|
'orchestra.apps.webapps.types.PHP4App',
|
||||||
'orchestra.apps.webapps.types.StaticApp',
|
'orchestra.apps.webapps.types.StaticApp',
|
||||||
|
@ -35,7 +38,10 @@ WEBAPPS_TYPES = getattr(settings, 'WEBAPPS_TYPES', (
|
||||||
'orchestra.apps.webapps.types.WordPressApp',
|
'orchestra.apps.webapps.types.WordPressApp',
|
||||||
))
|
))
|
||||||
|
|
||||||
|
WEBAPPS_UNDER_CONSTRUCTION_PATH = getattr(settings, 'WEBAPPS_UNDER_CONSTRUCTION_PATH',
|
||||||
|
# Server-side path where a under construction stock page is
|
||||||
|
# '/var/www/undercontruction/index.html',
|
||||||
|
'')
|
||||||
|
|
||||||
#WEBAPPS_TYPES_OVERRIDE = getattr(settings, 'WEBAPPS_TYPES_OVERRIDE', {})
|
#WEBAPPS_TYPES_OVERRIDE = getattr(settings, 'WEBAPPS_TYPES_OVERRIDE', {})
|
||||||
#for webapp_type, value in WEBAPPS_TYPES_OVERRIDE.iteritems():
|
#for webapp_type, value in WEBAPPS_TYPES_OVERRIDE.iteritems():
|
||||||
|
@ -79,7 +85,6 @@ WEBAPPS_PHP_DISABLED_FUNCTIONS = getattr(settings, 'WEBAPPS_PHP_DISABLED_FUNCTIO
|
||||||
|
|
||||||
WEBAPPS_ENABLED_OPTIONS = getattr(settings, 'WEBAPPS_ENABLED_OPTIONS', (
|
WEBAPPS_ENABLED_OPTIONS = getattr(settings, 'WEBAPPS_ENABLED_OPTIONS', (
|
||||||
'orchestra.apps.webapps.options.PublicRoot',
|
'orchestra.apps.webapps.options.PublicRoot',
|
||||||
'orchestra.apps.webapps.options.DirectoryProtection',
|
|
||||||
'orchestra.apps.webapps.options.Timeout',
|
'orchestra.apps.webapps.options.Timeout',
|
||||||
'orchestra.apps.webapps.options.Processes',
|
'orchestra.apps.webapps.options.Processes',
|
||||||
'orchestra.apps.webapps.options.PHPEnabledFunctions',
|
'orchestra.apps.webapps.options.PHPEnabledFunctions',
|
||||||
|
@ -140,7 +145,7 @@ WEBAPPS_DOKUWIKIMU_LISTEN = getattr(settings, 'WEBAPPS_DOKUWIKIMU_LISTEN',
|
||||||
|
|
||||||
|
|
||||||
WEBAPPS_DRUPALMU_SITES_PATH = getattr(settings, 'WEBAPPS_DRUPALMU_SITES_PATH',
|
WEBAPPS_DRUPALMU_SITES_PATH = getattr(settings, 'WEBAPPS_DRUPALMU_SITES_PATH',
|
||||||
'/home/httpd/htdocs/drupal-mu/sites/{site_name}')
|
'/home/httpd/htdocs/drupal-mu/sites/%(site_name)s')
|
||||||
|
|
||||||
WEBAPPS_DRUPALMU_LISTEN = getattr(settings, 'WEBAPPS_DRUPALMU_LISTEN',
|
WEBAPPS_DRUPALMU_LISTEN = getattr(settings, 'WEBAPPS_DRUPALMU_LISTEN',
|
||||||
'/opt/php/5.4/socks/drupal-mu.sock'
|
'/opt/php/5.4/socks/drupal-mu.sock'
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import os
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
|
@ -129,25 +131,31 @@ class PHPAppType(AppType):
|
||||||
socket_type = 'unix'
|
socket_type = 'unix'
|
||||||
if ':' in self.fpm_listen:
|
if ':' in self.fpm_listen:
|
||||||
socket_type = 'tcp'
|
socket_type = 'tcp'
|
||||||
socket = self.fpm_listen.format(context)
|
socket = self.fpm_listen % context
|
||||||
return ('fpm', socket_type, socket, webapp.get_path())
|
return ('fpm', socket_type, socket, webapp.get_path())
|
||||||
|
|
||||||
|
def get_context(self, webapp):
|
||||||
|
""" context used to format settings """
|
||||||
|
return {
|
||||||
|
'home': webapp.account.main_systemuser.get_home(),
|
||||||
|
'account': webapp.account.username,
|
||||||
|
'user': webapp.account.username,
|
||||||
|
'app_name': webapp.name,
|
||||||
|
}
|
||||||
|
|
||||||
def get_php_init_vars(self, webapp, per_account=False):
|
def get_php_init_vars(self, webapp, per_account=False):
|
||||||
"""
|
"""
|
||||||
process php options for inclusion on php.ini
|
process php options for inclusion on php.ini
|
||||||
per_account=True merges all (account, webapp.type) options
|
per_account=True merges all (account, webapp.type) options
|
||||||
"""
|
"""
|
||||||
init_vars = []
|
init_vars = {}
|
||||||
php_options = type(self).get_php_options()
|
|
||||||
options = webapp.options.all()
|
options = webapp.options.all()
|
||||||
if per_account:
|
if per_account:
|
||||||
options = webapp.account.webapps.filter(webapp_type=webapp.type)
|
options = webapp.account.webapps.filter(webapp_type=webapp.type)
|
||||||
php_options = [option.name for option in php_options]
|
php_options = [option.name for option in type(self).get_php_options()]
|
||||||
for opt in options:
|
for opt in options:
|
||||||
if opt.option_class in php_options:
|
if opt.name in php_options:
|
||||||
init_vars.append(
|
init_vars[opt.name] = opt.value
|
||||||
(opt.name, opt.value)
|
|
||||||
)
|
|
||||||
enabled_functions = []
|
enabled_functions = []
|
||||||
for value in options.filter(name='enabled_functions').values_list('value', flat=True):
|
for value in options.filter(name='enabled_functions').values_list('value', flat=True):
|
||||||
enabled_functions += enabled_functions.get().value.split(',')
|
enabled_functions += enabled_functions.get().value.split(',')
|
||||||
|
@ -156,9 +164,10 @@ class PHPAppType(AppType):
|
||||||
for function in settings.WEBAPPS_PHP_DISABLED_FUNCTIONS:
|
for function in settings.WEBAPPS_PHP_DISABLED_FUNCTIONS:
|
||||||
if function not in enabled_functions:
|
if function not in enabled_functions:
|
||||||
disabled_functions.append(function)
|
disabled_functions.append(function)
|
||||||
init_vars.append(
|
init_vars['dissabled_functions'] = ','.join(disabled_functions)
|
||||||
('dissabled_functions', ','.join(disabled_functions))
|
if settings.WEBAPPS_PHP_ERROR_LOG_PATH and 'error_log' not in init_vars:
|
||||||
)
|
context = self.get_context(webapp)
|
||||||
|
init_vars['error_log'] = settings.WEBAPPS_PHP_ERROR_LOG_PATH % context
|
||||||
return init_vars
|
return init_vars
|
||||||
|
|
||||||
|
|
||||||
|
@ -171,23 +180,37 @@ class PHP54App(PHPAppType):
|
||||||
icon = 'orchestra/icons/apps/PHPFPM.png'
|
icon = 'orchestra/icons/apps/PHPFPM.png'
|
||||||
|
|
||||||
|
|
||||||
class PHP52App(PHPAppType):
|
class PHP53App(PHPAppType):
|
||||||
name = 'php5.2-fcgid'
|
name = 'php5.3-fcgid'
|
||||||
php_version = 5.2
|
php_version = 5.3
|
||||||
verbose_name = "PHP 5.2 FCGID"
|
php_binary = '/usr/bin/php5-cgi'
|
||||||
help_text = _("This creates a PHP5.2 application under ~/webapps/<app_name><br>"
|
php_rc = '/etc/php5/cgi/'
|
||||||
|
verbose_name = "PHP 5.3 FCGID"
|
||||||
|
help_text = _("This creates a PHP5.3 application under ~/webapps/<app_name><br>"
|
||||||
"Apache-mod-fcgid will be used to execute PHP files.")
|
"Apache-mod-fcgid will be used to execute PHP files.")
|
||||||
icon = 'orchestra/icons/apps/PHPFCGI.png'
|
icon = 'orchestra/icons/apps/PHPFCGI.png'
|
||||||
|
|
||||||
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.format(context)
|
wrapper_path = settings.WEBAPPS_FCGID_PATH % context
|
||||||
return ('fcgi', webapp.get_path(), wrapper_path)
|
return ('fcgid', webapp.get_path(), wrapper_path)
|
||||||
|
|
||||||
|
|
||||||
class PHP4App(PHP52App):
|
class PHP52App(PHP53App):
|
||||||
|
name = 'php5.2-fcgid'
|
||||||
|
php_version = 5.2
|
||||||
|
php_binary = '/usr/bin/php5.2-cgi'
|
||||||
|
php_rc = '/etc/php5.2/cgi/'
|
||||||
|
verbose_name = "PHP 5.2 FCGID"
|
||||||
|
help_text = _("This creates a PHP5.2 application under ~/webapps/<app_name><br>"
|
||||||
|
"Apache-mod-fcgid will be used to execute PHP files.")
|
||||||
|
icon = 'orchestra/icons/apps/PHPFCGI.png'
|
||||||
|
|
||||||
|
|
||||||
|
class PHP4App(PHP53App):
|
||||||
name = 'php4-fcgid'
|
name = 'php4-fcgid'
|
||||||
php_version = 4
|
php_version = 4
|
||||||
|
php_binary = '/usr/bin/php4-cgi'
|
||||||
verbose_name = "PHP 4 FCGID"
|
verbose_name = "PHP 4 FCGID"
|
||||||
help_text = _("This creates a PHP4 application under ~/webapps/<app_name><br>"
|
help_text = _("This creates a PHP4 application under ~/webapps/<app_name><br>"
|
||||||
"Apache-mod-fcgid will be used to execute PHP files.")
|
"Apache-mod-fcgid will be used to execute PHP files.")
|
||||||
|
@ -213,7 +236,7 @@ class WebalizerApp(AppType):
|
||||||
option_groups = ()
|
option_groups = ()
|
||||||
|
|
||||||
def get_directive(self, webapp):
|
def get_directive(self, webapp):
|
||||||
return ('static', webapp.get_path())
|
return ('static', os.path.join(webapp.get_path(), '%(site_name)s/'))
|
||||||
|
|
||||||
|
|
||||||
class WordPressMuApp(PHPAppType):
|
class WordPressMuApp(PHPAppType):
|
||||||
|
|
|
@ -35,7 +35,7 @@ class DirectiveInline(admin.TabularInline):
|
||||||
if db_field.name == 'name':
|
if db_field.name == 'name':
|
||||||
# Help text based on select widget
|
# Help text based on select widget
|
||||||
kwargs['widget'] = DynamicHelpTextSelect(
|
kwargs['widget'] = DynamicHelpTextSelect(
|
||||||
'this.id.replace("name", "value")', self.DIECTIVES_HELP_TEXT
|
'this.id.replace("name", "value")', self.DIRECTIVES_HELP_TEXT
|
||||||
)
|
)
|
||||||
return super(DirectiveInline, self).formfield_for_dbfield(db_field, **kwargs)
|
return super(DirectiveInline, self).formfield_for_dbfield(db_field, **kwargs)
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ class WebsiteAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
)
|
)
|
||||||
form = WebsiteAdminForm
|
form = WebsiteAdminForm
|
||||||
filter_by_account_fields = ['domains']
|
filter_by_account_fields = ['domains']
|
||||||
list_prefetch_related = ('domains', 'contents__webapp')
|
list_prefetch_related = ('domains', 'content_set__webapp')
|
||||||
search_fields = ('name', 'account__username', 'domains__name')
|
search_fields = ('name', 'account__username', 'domains__name')
|
||||||
|
|
||||||
def display_domains(self, website):
|
def display_domains(self, website):
|
||||||
|
@ -86,7 +86,7 @@ class WebsiteAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
|
|
||||||
def display_webapps(self, website):
|
def display_webapps(self, website):
|
||||||
webapps = []
|
webapps = []
|
||||||
for content in website.contents.all():
|
for content in website.content_set.all():
|
||||||
webapp = content.webapp
|
webapp = content.webapp
|
||||||
url = change_url(webapp)
|
url = change_url(webapp)
|
||||||
name = "%s on %s" % (webapp.get_type_display(), content.path)
|
name = "%s on %s" % (webapp.get_type_display(), content.path)
|
||||||
|
|
|
@ -44,7 +44,7 @@ class Apache2Backend(ServiceController):
|
||||||
</VirtualHost>"""
|
</VirtualHost>"""
|
||||||
))
|
))
|
||||||
apache_conf = apache_conf.render(Context(context))
|
apache_conf = apache_conf.render(Context(context))
|
||||||
apache_conf += self.get_protections(site)
|
# apache_conf += self.get_protections(site)
|
||||||
context['apache_conf'] = apache_conf
|
context['apache_conf'] = apache_conf
|
||||||
|
|
||||||
self.append(textwrap.dedent("""\
|
self.append(textwrap.dedent("""\
|
||||||
|
@ -64,21 +64,21 @@ class Apache2Backend(ServiceController):
|
||||||
|
|
||||||
def commit(self):
|
def commit(self):
|
||||||
""" reload Apache2 if necessary """
|
""" reload Apache2 if necessary """
|
||||||
self.append('[[ $UPDATED == 1 ]] && service apache2 reload || true')
|
self.append('if [[ $UPDATED == 1 ]]; then service apache2 reload; fi')
|
||||||
|
|
||||||
def get_content_directives(self, site):
|
def get_content_directives(self, site):
|
||||||
directives = ''
|
directives = ''
|
||||||
for content in site.contents.all().order_by('-path'):
|
for content in site.content_set.all().order_by('-path'):
|
||||||
directive = content.webapp.get_directive()
|
directive = content.webapp.get_directive()
|
||||||
method, agrs = directive[0], directive[1:]
|
method, args = directive[0], directive[1:]
|
||||||
method = getattr(self, 'get_%s_directives' % method)
|
method = getattr(self, 'get_%s_directives' % method)
|
||||||
directives += method(content, *args)
|
directives += method(content, *args)
|
||||||
return directives
|
return directives
|
||||||
|
|
||||||
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['app_path'] = app_path % context
|
||||||
return "Alias %(location)s %(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,29 +95,26 @@ 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
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_fcgi_directives(self, content, app_path, wrapper_path):
|
def get_fcgid_directives(self, content, app_path, wrapper_path):
|
||||||
context = self.get_content_context(content)
|
context = self.get_content_context(content)
|
||||||
context.update({
|
context.update({
|
||||||
'app_path': app_path,
|
'app_path': app_path,
|
||||||
'wrapper_path': wrapper_path,
|
'wrapper_path': wrapper_path,
|
||||||
})
|
})
|
||||||
fcgid = 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>
|
||||||
""") % context
|
""") % context
|
||||||
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):
|
def get_ssl(self, site):
|
||||||
cert = settings.WEBSITES_DEFAULT_HTTPS_CERT
|
cert = settings.WEBSITES_DEFAULT_HTTPS_CERT
|
||||||
|
@ -129,54 +126,53 @@ class Apache2Backend(ServiceController):
|
||||||
SSLEngine on
|
SSLEngine on
|
||||||
SSLCertificateFile %s
|
SSLCertificateFile %s
|
||||||
SSLCertificateKeyFile %s\
|
SSLCertificateKeyFile %s\
|
||||||
""" % cert
|
""") % cert
|
||||||
)
|
|
||||||
return directives
|
return directives
|
||||||
|
|
||||||
def get_security(self, site):
|
def get_security(self, site):
|
||||||
directives = ''
|
directives = ''
|
||||||
for rules in site.options.filter(name='sec_rule_remove'):
|
for rules in site.directives.filter(name='sec_rule_remove'):
|
||||||
for rule in rules.value.split():
|
for rule in rules.value.split():
|
||||||
directives += "SecRuleRemoveById %i\n" % int(rule)
|
directives += "SecRuleRemoveById %i\n" % int(rule)
|
||||||
for modsecurity in site.options.filter(name='sec_rule_off'):
|
for modsecurity in site.directives.filter(name='sec_rule_off'):
|
||||||
directives += textwrap.dedent("""\
|
directives += textwrap.dedent("""\
|
||||||
<LocationMatch %s>
|
<LocationMatch %s>
|
||||||
SecRuleEngine Off
|
SecRuleEngine Off
|
||||||
</LocationMatch>\
|
</LocationMatch>\
|
||||||
""" % modsecurity.value)
|
""") % modsecurity.value
|
||||||
if directives:
|
if directives:
|
||||||
directives = '<IfModule mod_security2.c>\n%s\n</IfModule>' % directives
|
directives = '<IfModule mod_security2.c>\n%s\n</IfModule>' % directives
|
||||||
return directives
|
return directives
|
||||||
|
|
||||||
def get_redirect(self, site):
|
def get_redirect(self, site):
|
||||||
directives = ''
|
directives = ''
|
||||||
for redirect in site.options.filter(name='redirect'):
|
for redirect in site.directives.filter(name='redirect'):
|
||||||
if re.match(r'^.*[\^\*\$\?\)]+.*$', redirect.value):
|
if re.match(r'^.*[\^\*\$\?\)]+.*$', redirect.value):
|
||||||
directives += "RedirectMatch %s" % redirect.value
|
directives += "RedirectMatch %s" % redirect.value
|
||||||
else:
|
else:
|
||||||
directives += "Redirect %s" % redirect.value
|
directives += "Redirect %s" % redirect.value
|
||||||
return directives
|
return directives
|
||||||
|
|
||||||
def get_protections(self, site):
|
# def get_protections(self, site):
|
||||||
protections = ''
|
# protections = ''
|
||||||
context = self.get_context(site)
|
# context = self.get_context(site)
|
||||||
for protection in site.options.filter(name='directory_protection'):
|
# for protection in site.directives.filter(name='directory_protection'):
|
||||||
path, name, passwd = protection.value.split()
|
# path, name, passwd = protection.value.split()
|
||||||
path = os.path.join(context['root'], path)
|
# path = os.path.join(context['root'], path)
|
||||||
passwd = os.path.join(self.USER_HOME % context, passwd)
|
# passwd = os.path.join(self.USER_HOME % context, passwd)
|
||||||
protections += textwrap.dedent("""
|
# protections += textwrap.dedent("""
|
||||||
<Directory %s>
|
# <Directory %s>
|
||||||
AllowOverride All
|
# AllowOverride All
|
||||||
#AuthPAM_Enabled off
|
# #AuthPAM_Enabled off
|
||||||
AuthType Basic
|
# AuthType Basic
|
||||||
AuthName %s
|
# AuthName %s
|
||||||
AuthUserFile %s
|
# AuthUserFile %s
|
||||||
<Limit GET POST>
|
# <Limit GET POST>
|
||||||
require valid-user
|
# require valid-user
|
||||||
</Limit>
|
# </Limit>
|
||||||
</Directory>""" % (path, name, passwd)
|
# </Directory>""" % (path, name, passwd)
|
||||||
)
|
# )
|
||||||
return protections
|
# return protections
|
||||||
|
|
||||||
def enable_or_disable(self, site):
|
def enable_or_disable(self, site):
|
||||||
context = self.get_context(site)
|
context = self.get_context(site)
|
||||||
|
@ -184,27 +180,25 @@ class Apache2Backend(ServiceController):
|
||||||
self.append(textwrap.dedent("""\
|
self.append(textwrap.dedent("""\
|
||||||
if [[ ! -f %(sites_enabled)s ]]; then
|
if [[ ! -f %(sites_enabled)s ]]; then
|
||||||
a2ensite %(site_unique_name)s.conf
|
a2ensite %(site_unique_name)s.conf
|
||||||
else
|
UPDATED=1
|
||||||
UPDATED=0
|
fi""") % context
|
||||||
fi""" % context
|
)
|
||||||
))
|
|
||||||
else:
|
else:
|
||||||
self.append(textwrap.dedent("""\
|
self.append(textwrap.dedent("""\
|
||||||
if [[ -f %(sites_enabled)s ]]; then
|
if [[ -f %(sites_enabled)s ]]; then
|
||||||
a2dissite %(site_unique_name)s.conf;
|
a2dissite %(site_unique_name)s.conf;
|
||||||
else
|
UPDATED=1
|
||||||
UPDATED=0
|
fi""") % context
|
||||||
fi""" % context
|
)
|
||||||
))
|
|
||||||
|
|
||||||
def get_username(self, site):
|
def get_username(self, site):
|
||||||
option = site.options.filter(name='user_group').first()
|
option = site.directives.filter(name='user_group').first()
|
||||||
if option:
|
if option:
|
||||||
return option.value.split()[0]
|
return option.value.split()[0]
|
||||||
return site.account.username
|
return site.account.username
|
||||||
|
|
||||||
def get_groupname(self, site):
|
def get_groupname(self, site):
|
||||||
option = site.options.filter(name='user_group').first()
|
option = site.directives.filter(name='user_group').first()
|
||||||
if option and ' ' in option.value:
|
if option and ' ' in option.value:
|
||||||
user, group = option.value.split()
|
user, group = option.value.split()
|
||||||
return group
|
return group
|
||||||
|
@ -236,7 +230,6 @@ class Apache2Backend(ServiceController):
|
||||||
'location': content.path,
|
'location': content.path,
|
||||||
'app_name': content.webapp.name,
|
'app_name': content.webapp.name,
|
||||||
'app_path': content.webapp.get_path(),
|
'app_path': content.webapp.get_path(),
|
||||||
'fpm_port': content.webapp.get_fpm_port(),
|
|
||||||
})
|
})
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
@ -292,7 +285,7 @@ class Apache2Traffic(ServiceMonitor):
|
||||||
print sum
|
print sum
|
||||||
}' || [[ $? == 1 ]] && true
|
}' || [[ $? == 1 ]] && true
|
||||||
} | xargs echo ${OBJECT_ID}
|
} | xargs echo ${OBJECT_ID}
|
||||||
}""" % context))
|
}""") % context)
|
||||||
|
|
||||||
def monitor(self, site):
|
def monitor(self, site):
|
||||||
context = self.get_context(site)
|
context = self.get_context(site)
|
||||||
|
|
|
@ -20,18 +20,17 @@ class WebalizerBackend(ServiceController):
|
||||||
echo 'Webstats are coming soon' > %(webalizer_path)s/index.html
|
echo 'Webstats are coming soon' > %(webalizer_path)s/index.html
|
||||||
fi
|
fi
|
||||||
echo '%(webalizer_conf)s' > %(webalizer_conf_path)s
|
echo '%(webalizer_conf)s' > %(webalizer_conf_path)s
|
||||||
chown %(user)s:www-data %(webalizer_path)s""" % context
|
chown %(user)s:www-data %(webalizer_path)s""") % context
|
||||||
))
|
)
|
||||||
|
|
||||||
def delete(self, content):
|
def delete(self, content):
|
||||||
context = self.get_context(content)
|
context = self.get_context(content)
|
||||||
delete_webapp = not content.webapp.pk
|
delete_webapp = type(content.webapp).objects.filter(pk=content.webapp.pk).exists()
|
||||||
# TODO remove when confirmed that it works, otherwise create a second WebalizerBackend for WebApps
|
|
||||||
if delete_webapp:
|
if delete_webapp:
|
||||||
self.append("mv %(webapp_path)s %(webapp_path)s.deleted" % context)
|
self.append("mv %(webapp_path)s %(webapp_path)s.deleted" % context)
|
||||||
if delete_webapp or not content.webapp.contents.filter(website=content.website).exists():
|
if delete_webapp or not content.webapp.content_set.filter(website=content.website).exists():
|
||||||
self.append("mv %(webalizer_path)s %(webalizer_path)s.deleted" % context)
|
self.append("rm -fr %(webalizer_path)s" % context)
|
||||||
self.append("rm %(webalizer_conf_path)s" % context)
|
self.append("rm -f %(webalizer_conf_path)s" % context)
|
||||||
|
|
||||||
def get_context(self, content):
|
def get_context(self, content):
|
||||||
conf_file = "%s.conf" % content.website.unique_name
|
conf_file = "%s.conf" % content.website.unique_name
|
||||||
|
@ -88,6 +87,5 @@ class WebalizerBackend(ServiceController):
|
||||||
SearchEngine mamma.com query=
|
SearchEngine mamma.com query=
|
||||||
SearchEngine alltheweb.com query=
|
SearchEngine alltheweb.com query=
|
||||||
|
|
||||||
DumpSites yes""" % context
|
DumpSites yes""") % context
|
||||||
)
|
|
||||||
return context
|
return context
|
||||||
|
|
|
@ -10,9 +10,9 @@ from . import settings
|
||||||
|
|
||||||
# TODO multiple and unique validation support in the formset
|
# TODO multiple and unique validation support in the formset
|
||||||
class SiteDirective(Plugin):
|
class SiteDirective(Plugin):
|
||||||
HTTPD = 'httpd'
|
HTTPD = 'HTTPD'
|
||||||
SEC = 'sec'
|
SEC = 'ModSecurity'
|
||||||
SSL = 'ssl'
|
SSL = 'SSL'
|
||||||
|
|
||||||
help_text = ""
|
help_text = ""
|
||||||
unique = True
|
unique = True
|
||||||
|
|
|
@ -66,7 +66,8 @@ class Website(models.Model):
|
||||||
return {
|
return {
|
||||||
'home': self.account.main_systemuser.get_home(),
|
'home': self.account.main_systemuser.get_home(),
|
||||||
'account': self.account.username,
|
'account': self.account.username,
|
||||||
'name': self.name,
|
'user': self.account.username,
|
||||||
|
'site_name': self.name,
|
||||||
'unique_name': self.unique_name
|
'unique_name': self.unique_name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,10 +106,9 @@ class Directive(models.Model):
|
||||||
|
|
||||||
|
|
||||||
class Content(models.Model):
|
class Content(models.Model):
|
||||||
webapp = models.ForeignKey('webapps.WebApp', verbose_name=_("web application"),
|
# related_name is content_set to differentiate between website.content -> webapp
|
||||||
related_name='contents')
|
webapp = models.ForeignKey('webapps.WebApp', verbose_name=_("web application"))
|
||||||
website = models.ForeignKey('websites.Website', verbose_name=_("web site"),
|
website = models.ForeignKey('websites.Website', verbose_name=_("web site"))
|
||||||
related_name='contents')
|
|
||||||
path = models.CharField(_("path"), max_length=256, blank=True,
|
path = models.CharField(_("path"), max_length=256, blank=True,
|
||||||
validators=[validators.validate_url_path])
|
validators=[validators.validate_url_path])
|
||||||
|
|
||||||
|
@ -124,6 +124,8 @@ class Content(models.Model):
|
||||||
def clean(self):
|
def clean(self):
|
||||||
if not self.path.startswith('/'):
|
if not self.path.startswith('/'):
|
||||||
self.path = '/' + 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()
|
||||||
|
|
|
@ -43,7 +43,7 @@ class ContentSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
class WebsiteSerializer(AccountSerializerMixin, HyperlinkedModelSerializer):
|
class WebsiteSerializer(AccountSerializerMixin, HyperlinkedModelSerializer):
|
||||||
domains = RelatedDomainSerializer(many=True, allow_add_remove=True, required=False)
|
domains = RelatedDomainSerializer(many=True, allow_add_remove=True, required=False)
|
||||||
contents = ContentSerializer(required=False, many=True, allow_add_remove=True,
|
contents = ContentSerializer(required=False, many=True, allow_add_remove=True,
|
||||||
source='contents')
|
source='content_set')
|
||||||
options = OptionField(required=False)
|
options = OptionField(required=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
@ -36,7 +36,9 @@ MEDIA_URL = '/media/'
|
||||||
ALLOWED_HOSTS = '*'
|
ALLOWED_HOSTS = '*'
|
||||||
|
|
||||||
# Set this to True to wrap each HTTP request in a transaction on this database.
|
# Set this to True to wrap each HTTP request in a transaction on this database.
|
||||||
ATOMIC_REQUESTS = True
|
# ATOMIC REQUESTS do not wrap middlewares (orchestra.apps.orchestration.middlewares.OperationsMiddleware)
|
||||||
|
ATOMIC_REQUESTS = False
|
||||||
|
|
||||||
|
|
||||||
MIDDLEWARE_CLASSES = (
|
MIDDLEWARE_CLASSES = (
|
||||||
'django.middleware.gzip.GZipMiddleware',
|
'django.middleware.gzip.GZipMiddleware',
|
||||||
|
@ -46,9 +48,12 @@ MIDDLEWARE_CLASSES = (
|
||||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||||
'django.contrib.messages.middleware.MessageMiddleware',
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
'orchestra.core.caches.RequestCacheMiddleware',
|
'orchestra.core.caches.RequestCacheMiddleware',
|
||||||
|
# ATOMIC REQUESTS do not wrap middlewares
|
||||||
|
'orchestra.core.middlewares.TransactionMiddleware',
|
||||||
'orchestra.apps.orchestration.middlewares.OperationsMiddleware',
|
'orchestra.apps.orchestration.middlewares.OperationsMiddleware',
|
||||||
# Uncomment the next line for simple clickjacking protection:
|
# Uncomment the next line for simple clickjacking protection:
|
||||||
# 'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
# 'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
from django.db import connection, transaction
|
||||||
|
|
||||||
|
|
||||||
|
class TransactionMiddleware(object):
|
||||||
|
"""
|
||||||
|
Transaction middleware. If this is enabled, each view function will be run
|
||||||
|
with commit_on_response activated - that way a save() doesn't do a direct
|
||||||
|
commit, the commit is done when a successful response is created. If an
|
||||||
|
exception happens, the database is rolled back.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def process_request(self, request):
|
||||||
|
"""Enters transaction management"""
|
||||||
|
transaction.enter_transaction_management()
|
||||||
|
|
||||||
|
def process_exception(self, request, exception):
|
||||||
|
"""Rolls back the database and leaves transaction management"""
|
||||||
|
if transaction.is_dirty():
|
||||||
|
# This rollback might fail because of network failure for example.
|
||||||
|
# If rollback isn't possible it is impossible to clean the
|
||||||
|
# connection's state. So leave the connection in dirty state and
|
||||||
|
# let request_finished signal deal with cleaning the connection.
|
||||||
|
transaction.rollback()
|
||||||
|
transaction.leave_transaction_management()
|
||||||
|
|
||||||
|
def process_response(self, request, response):
|
||||||
|
"""Commits and leaves transaction management."""
|
||||||
|
if not transaction.get_autocommit():
|
||||||
|
if transaction.is_dirty():
|
||||||
|
# Note: it is possible that the commit fails. If the reason is
|
||||||
|
# closed connection or some similar reason, then there is
|
||||||
|
# little hope to proceed nicely. However, in some cases (
|
||||||
|
# deferred foreign key checks for exampl) it is still possible
|
||||||
|
# to rollback().
|
||||||
|
try:
|
||||||
|
transaction.commit()
|
||||||
|
except Exception:
|
||||||
|
# If the rollback fails, the transaction state will be
|
||||||
|
# messed up. It doesn't matter, the connection will be set
|
||||||
|
# to clean state after the request finishes. And, we can't
|
||||||
|
# clean the state here properly even if we wanted to, the
|
||||||
|
# connection is in transaction but we can't rollback...
|
||||||
|
transaction.rollback()
|
||||||
|
transaction.leave_transaction_management()
|
||||||
|
raise
|
||||||
|
transaction.leave_transaction_management()
|
||||||
|
return response
|
Loading…
Reference in New Issue