From e5e0d3aa968dbae21937e4440a2f296be4e9d0db Mon Sep 17 00:00:00 2001 From: Marc Aymerich Date: Mon, 16 Mar 2015 16:52:41 +0000 Subject: [PATCH] Websites backend directives ordered by location --- TODO.md | 6 +- orchestra/apps/webapps/settings.py | 12 ++-- orchestra/apps/websites/backends/apache.py | 70 +++++++++++++--------- 3 files changed, 51 insertions(+), 37 deletions(-) diff --git a/TODO.md b/TODO.md index ab595ef6..97d25523 100644 --- a/TODO.md +++ b/TODO.md @@ -199,11 +199,13 @@ Php binaries should have this format: /usr/bin/php5.2-cgi * Orchestra global search box on the header, based https://github.com/django/django/blob/master/django/contrib/admin/options.py#L866 and iterating over all registered services and inspectin its admin.search_fields -* contain error on plugin missing key (plugin dissabled): NOP, fail hard is better than silently +* contain error on plugin missing key (plugin dissabled): NOP, fail hard is better than silently, perhaps fail at starttime? apploading * contact.alternative_phone on a phone.tooltip, email:to * better validate options and directives (url locations, filesystem paths, etc..) * filter php deprecated options out based on version -* Todo get php_version for fcgid wrapper +* order virtualhost locations /hola / including directive + +* make sure that you understand the risks diff --git a/orchestra/apps/webapps/settings.py b/orchestra/apps/webapps/settings.py index ae9b844f..1b9de49f 100644 --- a/orchestra/apps/webapps/settings.py +++ b/orchestra/apps/webapps/settings.py @@ -41,12 +41,12 @@ WEBAPPS_TYPES = getattr(settings, 'WEBAPPS_TYPES', ( WEBAPPS_PHP_VERSIONS = getattr(settings, 'WEBAPPS_PHP_VERSIONS', ( - # Execution modle choose by ending with -fpm or -cgi - ('php-5.4-fpm', 'PHP 5.4 FPM'), - ('php-5.4-cgi', 'PHP 5.4 FCGID'), - ('php-5.3-cgi', 'PHP 5.3 FCGID'), - ('php-5.2-cgi', 'PHP 5.2 FCGID'), - ('php-4-cgi', 'PHP 4 FCGID'), + # Execution modle choose by ending -fpm or -cgi + ('5.4-fpm', 'PHP 5.4 FPM'), + ('5.4-cgi', 'PHP 5.4 FCGID'), + ('5.3-cgi', 'PHP 5.3 FCGID'), + ('5.2-cgi', 'PHP 5.2 FCGID'), + ('4-cgi', 'PHP 4 FCGID'), )) diff --git a/orchestra/apps/websites/backends/apache.py b/orchestra/apps/websites/backends/apache.py index dea37cda..8bc1edfd 100644 --- a/orchestra/apps/websites/backends/apache.py +++ b/orchestra/apps/websites/backends/apache.py @@ -31,7 +31,9 @@ class Apache2Backend(ServiceController): extra_conf += self.get_security(directives) extra_conf += self.get_redirects(directives) extra_conf += self.get_proxies(directives) - context['extra_conf'] = extra_conf + # Order extra conf directives based on directives (longer first) + extra_conf = sorted(extra_conf, key=lambda a: len(a[0]), reverse=True) + context['extra_conf'] = '\n'.join([conf for location, conf in extra_conf]) return Template(textwrap.dedent("""\ ServerName {{ site.domains.all|first }}\ @@ -97,8 +99,8 @@ class Apache2Backend(ServiceController): self.append('if [[ $UPDATED == 1 ]]; then service apache2 reload; fi') def get_content_directives(self, site): - directives = '' - for content in site.content_set.all().order_by('-path'): + directives = [] + for content in site.content_set.all(): directive = content.webapp.get_directive() method, args = directive[0], directive[1:] method = getattr(self, 'get_%s_directives' % method) @@ -108,7 +110,9 @@ class Apache2Backend(ServiceController): def get_static_directives(self, content, app_path): context = self.get_content_context(content) context['app_path'] = app_path % context - return "Alias %(location)s/ %(app_path)s/\n" % context + location = "%(location)s/" % context + directive = "Alias %(location)s/ %(app_path)s/" % context + return [(location, directive)] def get_fpm_directives(self, content, socket_type, socket, app_path): if socket_type == 'unix': @@ -124,11 +128,12 @@ class Apache2Backend(ServiceController): 'app_path': app_path, 'socket': socket, }) - return textwrap.dedent("""\ + location = "%(location)s/" % context + directives = textwrap.dedent("""\ ProxyPassMatch ^%(location)s/(.*\.php(/.*)?)$ {target} - Alias %(location)s/ %(app_path)s/ - """.format(target=target) % context + Alias %(location)s/ %(app_path)s/""".format(target=target) % context ) + return [(location, directives)] def get_fcgid_directives(self, content, app_path, wrapper_path): context = self.get_content_context(content) @@ -136,15 +141,16 @@ class Apache2Backend(ServiceController): 'app_path': app_path, 'wrapper_path': wrapper_path, }) - return textwrap.dedent("""\ + location = "%(location)s/" % context + directives = textwrap.dedent("""\ Alias %(location)s/ %(app_path)s/ ProxyPass %(location)s/ ! Options +ExecCGI AddHandler fcgid-script .php FcgidWrapper %(wrapper_path)s - - """) % context + """) % context + return [(location, directives)] def get_ssl(self, directives): config = '' @@ -157,39 +163,45 @@ class Apache2Backend(ServiceController): key = directives.get('ssl_key') if key: config += "SSLCertificateKeyFile %s\n" % key[0] - return config + return [('', config)] def get_security(self, directives): - config = '' + security = [] for rules in directives.get('sec_rule_remove', []): for rule in rules.value.split(): - config += "SecRuleRemoveById %i\n" % int(rule) - for modsecurity in directives.get('sec_engine', []): - config += textwrap.dedent("""\ + sec_rule = "SecRuleRemoveById %i" % int(rule) + security.append(('', sec_rule)) + for location in directives.get('sec_engine', []): + sec_rule = textwrap.dedent("""\ SecRuleEngine off - - """) % modsecurity - return config + """) % location + security.append((location, sec_rule)) + return security def get_redirects(self, directives): - config = '' + redirects = [] for redirect in directives.get('redirect', []): - source, target = redirect.split() + location, target = redirect.split() if re.match(r'^.*[\^\*\$\?\)]+.*$', redirect): - config += "RedirectMatch %s %s\n" % (source, target) + redirect = "RedirectMatch %s %s" % (location, target) else: - config += "Redirect %s %s\n" % (source, target) - return config + redirect = "Redirect %s %s" % (location, target) + redirects.append((location, redirect)) + return redirects def get_proxies(self, directives): - config = '' + proxies = [] for proxy in directives.get('proxy', []): - source, target = proxy.split() - source = normurlpath(source) - config += 'ProxyPass %s %s\n' % (source, target) - config += 'ProxyPassReverse %s %s\n' % (source, target) - return config + location, target = proxy.split() + location = normurlpath(source) + proxy = textwrap.dedent("""\ + ProxyPass {location} {target} + ProxyPassReverse {location} {target}""".format( + location=location, target=target) + ) + proxies.append((location, proxy)) + return proxies # def get_protections(self, site): # protections = ''