From 43d70fe83d77d1c3168a6f322083de928f4f8dc8 Mon Sep 17 00:00:00 2001 From: Marc Aymerich Date: Tue, 21 Apr 2015 14:14:07 +0000 Subject: [PATCH] Added multiple IPs support per virtualhost --- orchestra/admin/filters.py | 18 ------------ orchestra/contrib/bills/actions.py | 1 + orchestra/contrib/bills/admin.py | 29 +++++++++++++++++-- .../management/commands/orchestrate.py | 14 +++++---- orchestra/contrib/resources/admin.py | 6 ++-- orchestra/contrib/services/admin.py | 5 ++-- orchestra/contrib/webapps/backends/php.py | 4 +-- orchestra/contrib/websites/backends/apache.py | 12 ++++---- orchestra/contrib/websites/settings.py | 4 +-- 9 files changed, 55 insertions(+), 38 deletions(-) delete mode 100644 orchestra/admin/filters.py diff --git a/orchestra/admin/filters.py b/orchestra/admin/filters.py deleted file mode 100644 index 27e4e276..00000000 --- a/orchestra/admin/filters.py +++ /dev/null @@ -1,18 +0,0 @@ -from django.contrib.admin import SimpleListFilter -from django.utils.translation import ugettext as _ - - -class UsedContentTypeFilter(SimpleListFilter): - title = _('Content type') - parameter_name = 'content_type' - - def lookups(self, request, model_admin): - qset = model_admin.model._default_manager.all().order_by() - result = () - for pk, name in qset.values_list('content_type', 'content_type__model').distinct(): - result += ((str(pk), name.capitalize()),) - return result - - def queryset(self, request, queryset): - if self.value(): - return queryset.filter(content_type=self.value()) diff --git a/orchestra/contrib/bills/actions.py b/orchestra/contrib/bills/actions.py index fdebbd40..ce638b5a 100644 --- a/orchestra/contrib/bills/actions.py +++ b/orchestra/contrib/bills/actions.py @@ -183,4 +183,5 @@ def copy_lines(modeladmin, request, queryset): def delete_lines(modeladmin, request, queryset): + # Call contrib.admin delete action if all lines in open bill pass diff --git a/orchestra/contrib/bills/admin.py b/orchestra/contrib/bills/admin.py index af94358e..648940a1 100644 --- a/orchestra/contrib/bills/admin.py +++ b/orchestra/contrib/bills/admin.py @@ -100,11 +100,36 @@ class ClosedBillLineInline(BillLineInline): class BillLineAdmin(admin.ModelAdmin): - list_display = ('description', 'bill_link', 'rate', 'quantity', 'tax', 'subtotal') + list_display = ( + 'description', 'bill_link', 'rate', 'quantity', 'tax', 'subtotal', 'display_sublinetotal', + 'display_total' + ) actions = (actions.undo_billing, actions.move_lines, actions.copy_lines,) + list_filter = ('tax', ('bill', admin.RelatedOnlyFieldListFilter)) list_select_related = ('bill',) + search_fields = ('description', 'bill__number') bill_link = admin_link('bill') + + def display_sublinetotal(self, instance): + return instance.subline_total or '' + display_sublinetotal.short_description = _("Subline") + display_sublinetotal.admin_order_field = 'subline_total' + + def display_total(self, instance): + return round(instance.computed_total or 0, 2) + display_total.short_description = _("Total") + display_total.admin_order_field = 'computed_total' + + def get_queryset(self, request): + qs = super(BillLineAdmin, self).get_queryset(request) + qs = qs.annotate( + subline_total=Sum('sublines__total'), + computed_total=Sum( + (F('subtotal') + Coalesce(F('sublines__total'), 0)) * (1+F('tax')/100) + ), + ) + return qs class BillLineManagerAdmin(BillLineAdmin): @@ -119,7 +144,7 @@ class BillLineManagerAdmin(BillLineAdmin): bill_ids = GET.pop('ids', None) if bill_ids: request.GET = GET - bill_ids = list(map(int, bill_ids.split(','))) + bill_ids = list(map(int, bill_ids)) self.bill_ids = bill_ids if bill_ids and len(bill_ids) == 1: bill_url = reverse('admin:bills_bill_change', args=(bill_ids[0],)) diff --git a/orchestra/contrib/orchestration/management/commands/orchestrate.py b/orchestra/contrib/orchestration/management/commands/orchestrate.py index b76dddee..a18da0fc 100644 --- a/orchestra/contrib/orchestration/management/commands/orchestrate.py +++ b/orchestra/contrib/orchestration/management/commands/orchestrate.py @@ -22,9 +22,9 @@ class Command(BaseCommand): parser.add_argument('--action', action='store', dest='action', default='save', help='Executes action. Defaults to "save".') parser.add_argument('--servers', action='store', dest='servers', - default='save', help='Overrides route server resolution with the provided server.') + default='', help='Overrides route server resolution with the provided server.') parser.add_argument('--backends', action='store', dest='backends', - default='save', help='Overrides backend.') + default='', help='Overrides backend.') parser.add_argument('--listbackends', action='store_true', dest='list_backends', default=False, help='List available baclends.') parser.add_argument('--dry-run', action='store_true', dest='dry', default=False, @@ -39,8 +39,8 @@ class Command(BaseCommand): model = get_model(*options['model'].split('.')) action = options.get('action') interactive = options.get('interactive') - servers = options.get('servers', '').split(',') - backends = options.get('backends', '').split(',') + servers = options.get('servers') + backends = options.get('backends') if (servers and not backends) or (not servers and backends): raise CommandError("--backends and --servers go in tandem.") dry = options.get('dry') @@ -53,13 +53,17 @@ class Command(BaseCommand): route_cache = {} queryset = model.objects.filter(**kwargs).order_by('id') if servers: + servers = servers.split(',') + backends = backends.split(',') server_objects = [] # Get and create missing Servers for server in servers: try: server = Server.objects.get(address=server) except Server.DoesNotExist: - server = Server.objects.create(name=server, address=server) + server = Server(name=server, address=server) + server.full_clean() + server.save() server_objects.append(server) # Generate operations for the given backend for instance in queryset: diff --git a/orchestra/contrib/resources/admin.py b/orchestra/contrib/resources/admin.py index 609d29d6..f8470c00 100644 --- a/orchestra/contrib/resources/admin.py +++ b/orchestra/contrib/resources/admin.py @@ -8,7 +8,6 @@ from django.utils.functional import cached_property from django.utils.translation import ungettext, ugettext, ugettext_lazy as _ from orchestra.admin import ExtendedModelAdmin -from orchestra.admin.filters import UsedContentTypeFilter from orchestra.admin.utils import insertattr, get_modeladmin, admin_link, admin_date from orchestra.contrib.orchestration.models import Route from orchestra.core import services @@ -27,7 +26,10 @@ class ResourceAdmin(ExtendedModelAdmin): ) list_display_links = ('id', 'verbose_name') list_editable = ('default_allocation', 'crontab', 'is_active',) - list_filter = (UsedContentTypeFilter, 'aggregation', 'on_demand', 'disable_trigger') + list_filter = ( + ('content_type', admin.RelatedOnlyFieldListFilter), 'aggregation', 'on_demand', + 'disable_trigger' + ) fieldsets = ( (None, { 'fields': ('verbose_name', 'name', 'content_type', 'aggregation'), diff --git a/orchestra/contrib/services/admin.py b/orchestra/contrib/services/admin.py index 0533da8e..0bddbb2a 100644 --- a/orchestra/contrib/services/admin.py +++ b/orchestra/contrib/services/admin.py @@ -7,7 +7,6 @@ from django.utils import timezone from django.utils.translation import ugettext_lazy as _ from orchestra.admin import ChangeViewActionsMixin -from orchestra.admin.filters import UsedContentTypeFilter from orchestra.core import services from .actions import update_orders, view_help, clone @@ -18,7 +17,9 @@ class ServiceAdmin(ChangeViewActionsMixin, admin.ModelAdmin): list_display = ( 'description', 'content_type', 'handler_type', 'num_orders', 'is_active' ) - list_filter = ('is_active', 'handler_type', UsedContentTypeFilter) + list_filter = ( + 'is_active', 'handler_type', ('content_type', admin.RelatedOnlyFieldListFilter), + ) fieldsets = ( (None, { 'classes': ('wide',), diff --git a/orchestra/contrib/webapps/backends/php.py b/orchestra/contrib/webapps/backends/php.py index b60b14f1..c89ee6ef 100644 --- a/orchestra/contrib/webapps/backends/php.py +++ b/orchestra/contrib/webapps/backends/php.py @@ -106,13 +106,13 @@ class PHPBackend(WebAppServiceMixin, ServiceController): echo -n "$state" > /dev/shm/restart.apache2 if [[ $UPDATED_APACHE -eq 1 ]]; then if [[ $locked == 0 ]]; then - service apache2 reload + service apache2 status && service apache2 reload || service apache2 start else echo "PHPBackend RESTART" >> /dev/shm/restart.apache2 fi elif [[ "$state" =~ .*RESTART$ ]]; then rm /dev/shm/restart.apache2 - service apache2 reload + service apache2 status && service apache2 reload || service apache2 start fi """) ) diff --git a/orchestra/contrib/websites/backends/apache.py b/orchestra/contrib/websites/backends/apache.py index a180b2eb..e012f540 100644 --- a/orchestra/contrib/websites/backends/apache.py +++ b/orchestra/contrib/websites/backends/apache.py @@ -40,7 +40,7 @@ class Apache2Backend(ServiceController): 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("""\ - + IncludeOptional /etc/apache2/site[s]-override/{{ site_unique_name }}.con[f] ServerName {{ server_name }}\ {% if server_alias %} @@ -59,7 +59,7 @@ class Apache2Backend(ServiceController): def render_redirect_https(self, context): context['port'] = self.HTTP_PORT return Template(textwrap.dedent(""" - + ServerName {{ server_name }}\ {% if server_alias %} ServerAlias {{ server_alias|join:' ' }}{% endif %}\ @@ -127,13 +127,13 @@ class Apache2Backend(ServiceController): echo -n "$state" > /dev/shm/restart.apache2 if [[ $UPDATED == 1 ]]; then if [[ $locked == 0 ]]; then - service apache2 reload + service apache2 satus && service apache2 reload || service apache2 start else echo "Apache2Backend RESTART" >> /dev/shm/restart.apache2 fi elif [[ "$state" =~ .*RESTART$ ]]; then rm /dev/shm/restart.apache2 - service apache2 reload + service apache2 satus && service apache2 reload || service apache2 start fi""") ) super(Apache2Backend, self).commit() @@ -332,7 +332,7 @@ class Apache2Backend(ServiceController): context = { 'site': site, 'site_name': site.name, - 'ip': settings.WEBSITES_DEFAULT_IP, + 'ips': settings.WEBSITES_DEFAULT_IPS, 'site_unique_name': site.unique_name, 'user': self.get_username(site), 'group': self.get_groupname(site), @@ -344,6 +344,8 @@ class Apache2Backend(ServiceController): 'error_log': site.get_www_error_log_path(), 'banner': self.get_banner(), } + if not context['ips']: + raise ValueError("WEBSITES_DEFAULT_IPS is empty.") return replace(context, "'", '"') def set_content_context(self, content, context): diff --git a/orchestra/contrib/websites/settings.py b/orchestra/contrib/websites/settings.py index 45b3646c..fd33798d 100644 --- a/orchestra/contrib/websites/settings.py +++ b/orchestra/contrib/websites/settings.py @@ -26,9 +26,9 @@ WEBSITES_DEFAULT_PROTOCOL = getattr(settings, 'WEBSITES_DEFAULT_PROTOCOL', ) -WEBSITES_DEFAULT_IP = getattr(settings, 'WEBSITES_DEFAULT_IP', +WEBSITES_DEFAULT_IPS = getattr(settings, 'WEBSITES_DEFAULT_IPS', ( '*' -) +)) WEBSITES_DOMAIN_MODEL = getattr(settings, 'WEBSITES_DOMAIN_MODEL',