Fixes on resources

This commit is contained in:
Marc Aymerich 2014-10-27 13:29:02 +00:00
parent 3b4b69e9a2
commit d3727f0565
27 changed files with 184 additions and 77 deletions

View File

@ -180,4 +180,7 @@ Remember that, as always with QuerySets, any subsequent chained methods which im
* Subdomain saving should not trigger bind slave
* Domain account change, unselected checkbox: migrate subdomains
* multiple files monitoring
* prevent adding local email addresses on account.contacts account.email
* Resource monitoring without ROUTE alert or explicit error

View File

@ -10,7 +10,7 @@ from orchestra.apps.accounts.admin import AccountAdminMixin
from orchestra.utils import apps
from .actions import view_zone
from .forms import RecordInlineFormSet, DomainAdminForm
from .forms import RecordInlineFormSet, CreateDomainAdminForm
from .filters import TopDomainListFilter
from .models import Domain, Record
@ -54,11 +54,11 @@ class DomainInline(admin.TabularInline):
class DomainAdmin(ChangeListDefaultFilter, AccountAdminMixin, ExtendedModelAdmin):
# TODO name link
fields = ('name', ('account', 'migrate_subdomains'),)
list_display = (
'structured_name', 'display_is_top', 'websites', 'account_link'
)
add_fields = ('name', 'account')
fields = ('name', 'account_link')
inlines = [RecordInline, DomainInline]
list_filter = [TopDomainListFilter]
change_readonly_fields = ('name',)
@ -66,7 +66,7 @@ class DomainAdmin(ChangeListDefaultFilter, AccountAdminMixin, ExtendedModelAdmin
default_changelist_filters = (
('top_domain', 'True'),
)
form = DomainAdminForm
add_form = CreateDomainAdminForm
change_view_actions = [view_zone]
def structured_name(self, domain):
@ -112,11 +112,11 @@ class DomainAdmin(ChangeListDefaultFilter, AccountAdminMixin, ExtendedModelAdmin
qs = qs.prefetch_related('websites')
return qs
def save_related(self, request, form, formsets, change):
super(DomainAdmin, self).save_related(request, form, formsets, change)
if form.cleaned_data['migrate_subdomains']:
domain = form.instance
domain.subdomains.update(account_id=domain.account_id)
# def save_related(self, request, form, formsets, change):
# super(DomainAdmin, self).save_related(request, form, formsets, change)
# if form.cleaned_data['migrate_subdomains']:
# domain = form.instance
# domain.subdomains.update(account_id=domain.account_id)
admin.site.register(Domain, DomainAdmin)

View File

@ -86,12 +86,14 @@ class Bind9MasterDomainBackend(ServiceController):
return self.get_servers(domain, Bind9SlaveDomainBackend)
def get_context(self, domain):
slaves = self.get_slaves(domain)
context = {
'name': domain.name,
'zone_path': settings.DOMAINS_ZONE_PATH % {'name': domain.name},
'subdomains': domain.subdomains.all(),
'banner': self.get_banner(),
'slaves': '; '.join(self.get_slaves(domain)) or 'none',
'slaves': '; '.join(slaves) or 'none',
'also_notify': '; '.join(slaves) + ';' if slaves else '',
}
context.update({
'conf_path': settings.DOMAINS_MASTERS_PATH,
@ -101,6 +103,7 @@ class Bind9MasterDomainBackend(ServiceController):
type master;
file "%(zone_path)s";
allow-transfer { %(slaves)s; };
also-notify { %(also_notify)s };
notify yes;
};""" % context)
})

View File

@ -7,13 +7,13 @@ from .helpers import domain_for_validation
from .models import Domain
class DomainAdminForm(forms.ModelForm):
migrate_subdomains = forms.BooleanField(label=_("Migrate subdomains"), required=False,
initial=False, help_text=_("Propagate the account owner change to subdomains."))
class CreateDomainAdminForm(forms.ModelForm):
# migrate_subdomains = forms.BooleanField(label=_("Migrate subdomains"), required=False,
# initial=False, help_text=_("Propagate the account owner change to subdomains."))
def clean(self):
""" inherit related top domain account, when exists """
cleaned_data = super(DomainAdminForm, self).clean()
cleaned_data = super(CreateDomainAdminForm, self).clean()
if not cleaned_data['account']:
domain = Domain(name=cleaned_data['name'])
top = domain.get_top()

View File

@ -182,6 +182,7 @@ class Record(models.Model):
def clean(self):
""" validates record value based on its type """
# validate value
self.value = self.value.lower().strip()
mapp = {
self.MX: validators.validate_mx_record,
self.NS: validators.validate_zone_label,

View File

@ -12,9 +12,8 @@ from django.utils.translation import ugettext_lazy as _
from markdown import markdown
from orchestra.admin import ChangeListDefaultFilter, ExtendedModelAdmin#, ChangeViewActions
from orchestra.admin.utils import (admin_link, admin_colored, wrap_admin_view,
admin_date)
from orchestra.apps.contacts import settings as contacts_settings
from orchestra.admin.utils import admin_link, admin_colored, wrap_admin_view, admin_date
from orchestra.apps.contacts.models import Contact
from .actions import (reject_tickets, resolve_tickets, take_tickets, close_tickets,
mark_as_unread, mark_as_read, set_default_queue)
@ -311,7 +310,7 @@ class QueueAdmin(admin.ModelAdmin):
def get_list_display(self, request):
""" show notifications """
list_display = list(self.list_display)
for value, verbose in contacts_settings.CONTACTS_EMAIL_USAGES:
for value, verbose in Contact.EMAIL_USAGES:
def display_notify(queue, notify=value):
return notify in queue.notify
display_notify.short_description = verbose

View File

@ -102,7 +102,8 @@ class MailmanBackend(ServiceController):
for address in self.addresses:
context['address'] = address
self.append('sed -i "s/^.*\s%(name)s%(address)s\s*$//" %(virtual_alias)s' % context)
self.append("rmlist -a %(name)s" % context)
# TODO remove
self.append("echo rmlist -a %(name)s" % context)
def commit(self):
context = self.get_context_files()
@ -172,7 +173,7 @@ class MailmanTraffic(ServiceMonitor):
}
class MailmanTraffic(ServiceMonitor):
class MailmanSubscribers(ServiceMonitor):
model = 'lists.List'
verbose_name = _("Mailman subscribers")

View File

@ -1,6 +1,7 @@
from django import forms
from django.utils.translation import ugettext_lazy as _
from orchestra import settings as orchestra_settings
from orchestra.core.validators import validate_password
from orchestra.forms.widgets import ReadOnlyWidget
@ -16,7 +17,7 @@ class CleanAddressMixin(object):
class ListCreationForm(CleanAddressMixin, forms.ModelForm):
password1 = forms.CharField(label=_("Password"),
password1 = forms.CharField(label=_("Password"), validators=[validate_password],
widget=forms.PasswordInput)
password2 = forms.CharField(label=_("Password confirmation"),
widget=forms.PasswordInput,
@ -24,7 +25,13 @@ class ListCreationForm(CleanAddressMixin, forms.ModelForm):
def __init__(self, *args, **kwargs):
super(ListCreationForm, self).__init__(*args, **kwargs)
self.fields['password1'].validators.append(validate_password)
if orchestra_settings.ORCHESTRA_MIGRATION_MODE:
self.fields['password1'].widget = forms.HiddenInput()
self.fields['password1'].required = False
self.fields['password2'].widget = forms.HiddenInput()
self.fields['password2'].required = False
self.fields['admin_email'].widget = forms.HiddenInput()
self.fields['admin_email'].required = False
def clean_password2(self):
password1 = self.cleaned_data.get("password1")
@ -36,6 +43,7 @@ class ListCreationForm(CleanAddressMixin, forms.ModelForm):
def save(self, commit=True):
obj = super(ListCreationForm, self).save(commit=commit)
if not orchestra_settings.ORCHESTRA_MIGRATION_MODE:
obj.set_password(self.cleaned_data["password1"])
return obj

View File

@ -46,8 +46,8 @@ class PasswdVirtualUserBackend(ServiceController):
fi""" % context))
def generate_filter(self, mailbox, context):
self.append("doveadm mailbox create -u %(username)s Spam" % context) # TODO override webmail filters???
context['filtering_path'] = os.path.join(context['home'], '.dovecot.sieve')
self.append("doveadm mailbox create -u %(username)s Spam" % context)
context['filtering_path'] = settings.MAILBOXES_SIEVE_PATH % context
filtering = mailbox.get_filtering()
if filtering:
context['filtering'] = '# %(banner)s\n' + filtering

View File

@ -14,7 +14,7 @@ class MailboxForm(forms.ModelForm):
# TODO keep track of this ticket for future reimplementation
# https://code.djangoproject.com/ticket/897
addresses = forms.ModelMultipleChoiceField(queryset=Address.objects, required=False,
widget=widgets.FilteredSelectMultiple(verbose_name=_('Pizzas'), is_stacked=False))
widget=widgets.FilteredSelectMultiple(verbose_name=_('addresses'), is_stacked=False))
def __init__(self, *args, **kwargs):
super(MailboxForm, self).__init__(*args, **kwargs)

View File

@ -8,7 +8,6 @@ from orchestra.core import services
from . import validators, settings
# TODO rename app to mailboxes
class Mailbox(models.Model):
CUSTOM = 'CUSTOM'

View File

@ -1,3 +1,4 @@
import os
import textwrap
from django.conf import settings
@ -10,6 +11,10 @@ MAILBOXES_DOMAIN_MODEL = getattr(settings, 'MAILBOXES_DOMAIN_MODEL', 'domains.Do
MAILBOXES_HOME = getattr(settings, 'MAILBOXES_HOME', '/home/%(name)s/')
MAILBOXES_SIEVE_PATH = getattr(settings, 'MAILBOXES_SIEVE_PATH',
os.path.join(MAILBOXES_HOME, 'Maildir/sieve/orchestra.sieve'))
MAILBOXES_SIEVETEST_PATH = getattr(settings, 'MAILBOXES_SIEVETEST_PATH', '/dev/shm')

View File

@ -0,0 +1,21 @@
from django.contrib import messages
from django.db import transaction
from django.shortcuts import redirect
from django.utils.translation import ungettext, ugettext_lazy as _
@transaction.atomic
def run_monitor(modeladmin, request, queryset):
for resource in queryset:
resource.monitor()
modeladmin.log_change(request, resource, _("Run monitors"))
num = len(queryset)
msg = ungettext(
_("One selected resource has been monitored."),
_("%s selected resource have been monitored.") % num,
num)
modeladmin.message_user(request, msg)
referer = request.META.get('HTTP_REFERER')
if referer:
return redirect(referer)
run_monitor.url_name = 'monitor'

View File

@ -1,8 +1,9 @@
from django.contrib import admin, messages
from django.contrib.contenttypes import generic
from django.core.urlresolvers import reverse
from django.utils.functional import cached_property
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ugettext, ugettext_lazy as _
from orchestra.admin import ExtendedModelAdmin
from orchestra.admin.filters import UsedContentTypeFilter
@ -10,6 +11,7 @@ from orchestra.admin.utils import insertattr, get_modeladmin, admin_link, admin_
from orchestra.core import services
from orchestra.utils import database_ready
from .actions import run_monitor
from .forms import ResourceForm
from .models import Resource, ResourceData, MonitorData
@ -66,27 +68,49 @@ class ResourceAdmin(ExtendedModelAdmin):
return super(ResourceAdmin, self).formfield_for_dbfield(db_field, **kwargs)
class ResourceDataAdmin(admin.ModelAdmin):
class ResourceDataAdmin(ExtendedModelAdmin):
list_display = (
'id', 'resource_link', 'used', 'allocated', 'updated_at', 'content_object_link'
'id', 'resource_link', 'content_object_link', 'used', 'allocated', 'display_unit',
'display_updated'
)
list_filter = ('resource',)
readonly_fields = ('content_object_link',)
add_fields = ('resource', 'content_type', 'object_id', 'used', 'updated_at', 'allocated')
fields = (
'resource_link', 'content_type', 'content_object_link', 'used', 'display_updated',
'allocated', 'display_unit'
)
readonly_fields = ('display_unit',)
change_readonly_fields = (
'resource_link', 'content_type', 'content_object_link', 'used', 'display_updated',
'display_unit'
)
actions = (run_monitor,)
change_view_actions = actions
ordering = ('-updated_at',)
resource_link = admin_link('resource')
content_object_link = admin_link('content_object')
display_updated = admin_date('updated_at', short_description=_("Updated"))
def display_unit(self, data):
return data.unit
display_unit.short_description = _("Unit")
display_unit.admin_order_field = 'resource__unit'
def get_queryset(self, request):
queryset = super(ResourceDataAdmin, self).get_queryset(request)
return queryset.prefetch_related('content_object')
class MonitorDataAdmin(admin.ModelAdmin):
list_display = ('id', 'monitor', 'created_at', 'value', 'content_object_link')
class MonitorDataAdmin(ExtendedModelAdmin):
list_display = ('id', 'monitor', 'display_created', 'value', 'content_object_link')
list_filter = ('monitor',)
readonly_fields = ('content_object_link',)
add_fields = ('monitor', 'content_type', 'object_id', 'created_at', 'value')
fields = ('monitor', 'content_type', 'content_object_link', 'display_created', 'value')
change_readonly_fields = fields
content_object_link = admin_link('content_object')
display_created = admin_date('created_at', short_description=_("Created"))
def get_queryset(self, request):
queryset = super(MonitorDataAdmin, self).get_queryset(request)
@ -109,10 +133,21 @@ def resource_inline_factory(resources):
def forms(self, resources=resources):
forms = []
resources_copy = list(resources)
for i, data in enumerate(self.queryset):
queryset = self.queryset
if self.instance.pk:
# Create missing resource data
queryset = list(queryset)
queryset_resources = [data.resource for data in queryset]
for resource in resources:
if resource not in queryset_resources:
data = resource.dataset.create(content_object=self.instance)
queryset.append(data)
# Existing dataset
for i, data in enumerate(queryset):
forms.append(self._construct_form(i, resource=data.resource))
resources_copy.remove(data.resource)
for i, resource in enumerate(resources_copy, len(self.queryset)):
# Missing dataset
for i, resource in enumerate(resources_copy, len(queryset)):
forms.append(self._construct_form(i, resource=resource))
return forms
@ -123,9 +158,9 @@ def resource_inline_factory(resources):
formset = ResourceInlineFormSet
can_delete = False
fields = (
'verbose_name', 'used', 'display_updated', 'allocated', 'unit'
'verbose_name', 'display_used', 'display_updated', 'allocated', 'unit',
)
readonly_fields = ('used', 'display_updated')
readonly_fields = ('display_used', 'display_updated')
class Media:
css = {
@ -134,9 +169,20 @@ def resource_inline_factory(resources):
display_updated = admin_date('updated_at', default=_("Never"))
def display_used(self, data):
update_link = ''
if data.pk:
url = reverse('admin:resources_resourcedata_monitor', args=(data.pk,))
update_link = '<a href="%s"><strong>%s</strong></a>' % (url, ugettext("Update"))
if data.used is not None:
return '%s %s %s' % (data.used, data.resource.unit, update_link)
return _("Unknonw %s") % update_link
display_used.short_description = _("Used")
def has_add_permission(self, *args, **kwargs):
""" Hidde add another """
return False
return ResourceInline

View File

@ -50,7 +50,7 @@ class ServiceMonitor(ServiceBackend):
data = self.get_last_data(object_id)
if data is None:
return self.current_date - datetime.timedelta(days=1)
return data.date
return data.created_at
def process(self, line):
""" line -> object_id, value """
@ -66,7 +66,7 @@ class ServiceMonitor(ServiceBackend):
line = line.strip()
object_id, value = self.process(line)
MonitorData.objects.create(monitor=name, object_id=object_id,
content_type=ct, value=value, date=self.current_date)
content_type=ct, value=value, created_at=self.current_date)
def execute(self, server):
log = super(ServiceMonitor, self).execute(server)

View File

@ -26,11 +26,11 @@ class ResourceForm(forms.ModelForm):
self.fields['allocated'].required = True
self.fields['allocated'].initial = self.resource.default_allocation
def has_changed(self):
""" Make sure resourcedata objects are created for all resources """
if not self.instance.pk:
return True
return super(ResourceForm, self).has_changed()
# def has_changed(self):
# """ Make sure resourcedata objects are created for all resources """
# if not self.instance.pk:
# return True
# return super(ResourceForm, self).has_changed()
def save(self, *args, **kwargs):
self.instance.resource_id = self.resource.pk

View File

@ -61,4 +61,4 @@ def compute_resource_usage(data):
has_result = True
else:
raise NotImplementedError("%s support not implemented" % data.period)
return result/resource.get_scale() if has_result else None
return float(result)/resource.get_scale() if has_result else None

View File

@ -3,6 +3,7 @@ from django.contrib.contenttypes.models import ContentType
from django.apps import apps
from django.db import models
from django.utils import timezone
from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _
from djcelery.models import PeriodicTask, CrontabSchedule
@ -11,7 +12,7 @@ from orchestra.models import queryset, fields
from orchestra.utils.paths import get_project_root
from orchestra.utils.system import run
from . import helpers
from . import helpers, tasks
from .backends import ServiceMonitor
from .validators import validate_scale
@ -127,7 +128,7 @@ class ResourceData(models.Model):
resource = models.ForeignKey(Resource, related_name='dataset', verbose_name=_("resource"))
content_type = models.ForeignKey(ContentType, verbose_name=_("content type"))
object_id = models.PositiveIntegerField(_("object id"))
used = models.PositiveIntegerField(_("used"), null=True)
used = models.DecimalField(_("used"), max_digits=16, decimal_places=2, null=True)
updated_at = models.DateTimeField(_("updated"), null=True)
allocated = models.PositiveIntegerField(_("allocated"), null=True, blank=True)
@ -160,6 +161,9 @@ class ResourceData(models.Model):
self.updated_at = timezone.now()
self.save(update_fields=['used', 'updated_at'])
def monitor(self):
tasks.monitor(self.resource_id, ids=(self.object_id,))
class MonitorData(models.Model):
""" Stores monitored data """
@ -167,7 +171,7 @@ class MonitorData(models.Model):
choices=ServiceMonitor.get_plugin_choices())
content_type = models.ForeignKey(ContentType, verbose_name=_("content type"))
object_id = models.PositiveIntegerField(_("object id"))
created_at = models.DateTimeField(_("created"), auto_now_add=True)
created_at = models.DateTimeField(_("created"))
value = models.DecimalField(_("value"), max_digits=16, decimal_places=2)
content_object = GenericForeignKey()
@ -179,6 +183,10 @@ class MonitorData(models.Model):
def __unicode__(self):
return str(self.monitor)
@cached_property
def unit(self):
return self.resource.unit
def create_resource_relation():
class ResourceHandler(object):

View File

@ -2,29 +2,39 @@ from celery import shared_task
from django.db.models.loading import get_model
from orchestra.apps.orchestration.models import BackendOperation as Operation
from orchestra.models.utils import get_model_field_path
from .backends import ServiceMonitor
from .models import ResourceData, Resource
@shared_task(name='resources.Monitor')
def monitor(resource_id):
resource = Resource.objects.get(pk=resource_id)
def monitor(resource_id, ids=None):
from .models import ResourceData, Resource
resource = Resource.objects.get(pk=resource_id)
resource_model = resource.content_type.model_class()
# Execute monitors
for monitor_name in resource.monitors:
backend = ServiceMonitor.get_backend(monitor_name)
model = get_model(backend.model)
kwargs = {}
if ids:
path = get_model_field_path(model, resource_model)
path = '%s__in' % ('__'.join(path) or 'id')
kwargs = {
path: ids
}
operations = []
# Execute monitor
for obj in model.objects.all():
for obj in model.objects.filter(**kwargs):
operations.append(Operation.create(backend, obj, Operation.MONITOR))
Operation.execute(operations)
kwargs = {'id__in': ids} if ids else {}
# Update used resources and trigger resource exceeded and revovery
operations = []
model = resource.content_type.model_class()
for obj in model.objects.all():
for obj in model.objects.filter(**kwargs):
data = ResourceData.get_or_create(obj, resource)
data.update()
if not resource.disable_trigger:

View File

@ -66,15 +66,14 @@ view_help.verbose_name = _("Help")
def clone(modeladmin, request, queryset):
service = queryset.get()
fields = (
'content_type_id', 'match', 'handler_type', 'is_active', 'ignore_superusers', 'billing_period',
'billing_point', 'is_fee', 'metric', 'nominal_price', 'tax', 'pricing_period',
'rate_algorithm', 'on_cancel', 'payment_style',
)
fields = modeladmin.get_fields(request)
fk_fields = ('content_type',)
query = []
for field in fields:
if field in fk_fields:
value = getattr(service, field + '_id')
else:
value = getattr(service, field)
field = field.replace('_id', '')
query.append('%s=%s' % (field, value))
opts = service._meta
url = reverse('admin:%s_%s_add' % (opts.app_label, opts.model_name))

View File

@ -186,7 +186,7 @@ class Service(models.Model):
nominal_price = models.DecimalField(_("nominal price"), max_digits=12,
decimal_places=2)
tax = models.PositiveIntegerField(_("tax"), choices=settings.SERVICES_SERVICE_TAXES,
default=settings.SERVICES_SERVICE_DEFAUL_TAX)
default=settings.SERVICES_SERVICE_DEFAULT_TAX)
pricing_period = models.CharField(_("pricing period"), max_length=16,
help_text=_("Time period that is used for computing the rate metric."),
choices=(

View File

@ -9,7 +9,7 @@ SERVICES_SERVICE_TAXES = getattr(settings, 'SERVICES_SERVICE_TAXES', (
(21, "21%"),
))
SERVICES_SERVICE_DEFAUL_TAX = getattr(settings, 'ORDERS_SERVICE_DFAULT_TAX', 0)
SERVICES_SERVICE_DEFAULT_TAX = getattr(settings, 'SERVICES_SERVICE_DEFAULT_TAX', 0)
SERVICES_SERVICE_ANUAL_BILLING_MONTH = getattr(settings, 'SERVICES_SERVICE_ANUAL_BILLING_MONTH', 1)

View File

@ -68,7 +68,7 @@ class SystemUserDisk(ServiceMonitor):
def monitor(self, user):
context = self.get_context(user)
self.append("du -s %(home)s | xargs echo %(object_id)s" % context)
self.append("du -s %(home)s | cut -f1 | xargs echo %(object_id)s" % context)
def get_context(self, user):
context = SystemUserBackend().get_context(user)

View File

@ -13,7 +13,8 @@ from . import settings
class WebApp(models.Model):
""" Represents a web application """
name = models.CharField(_("name"), max_length=128, validators=[validators.validate_name])
name = models.CharField(_("name"), max_length=128, validators=[validators.validate_name],
blank=settings.WEBAPPS_ALLOW_BLANK_NAME)
type = models.CharField(_("type"), max_length=32,
choices=dict_setting_to_choices(settings.WEBAPPS_TYPES),
default=settings.WEBAPPS_DEFAULT_TYPE)
@ -26,7 +27,7 @@ class WebApp(models.Model):
verbose_name_plural = _("Web Apps")
def __unicode__(self):
return self.name
return self.name or settings.WEBAPPS_BLANK_NAME
@cached
def get_options(self):

View File

@ -10,6 +10,12 @@ WEBAPPS_FPM_LISTEN = getattr(settings, 'WEBAPPS_FPM_LISTEN',
'127.0.0.1:%(fpm_port)s')
WEBAPPS_ALLOW_BLANK_NAME = getattr(settings, 'WEBAPPS_ALLOW_BLANK_NAME', False)
# Default name when blank
WEBAPPS_BLANK_NAME = getattr(settings, 'WEBAPPS_BLANK_NAME', 'webapp')
WEBAPPS_FPM_START_PORT = getattr(settings, 'WEBAPPS_FPM_START_PORT', 10000)

View File

@ -3,7 +3,6 @@ import os
import re
from django.template import Template, Context
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from orchestra.apps.orchestration import ServiceController
@ -191,17 +190,15 @@ class Apache2Traffic(ServiceMonitor):
verbose_name = _("Apache 2 Traffic")
def prepare(self):
current_date = timezone.localtime(self.current_date)
current_date = current_date.strftime("%Y%m%d%H%M%S")
current_date = self.current_date.strftime("%Y-%m-%d %H:%M:%S %Z")
self.append(textwrap.dedent("""\
function monitor () {
OBJECT_ID=$1
INI_DATE=$2
LOG_FILE="$3"
{
awk -v ini="${INI_DATE}" '
awk -v ini="${INI_DATE}" -v end="$(date '+%%Y%%m%%d%%H%%M%%S' -d '%s')" '
BEGIN {
end = "%s"
sum = 0
months["Jan"] = "01";
months["Feb"] = "02";
@ -235,12 +232,12 @@ class Apache2Traffic(ServiceMonitor):
def monitor(self, site):
context = self.get_context(site)
self.append('monitor %(object_id)i %(last_date)s "%(log_file)s"' % context)
self.append('monitor {object_id} $(date "+%Y%m%d%H%M%S" -d "{last_date}") "{log_file}"'.format(**context))
def get_context(self, site):
last_date = timezone.localtime(self.get_last_date(site.pk))
last_date = self.get_last_date(site.pk)
return {
'log_file': os.path.join(settings.WEBSITES_BASE_APACHE_LOGS, site.unique_name),
'last_date': last_date.strftime("%Y%m%d%H%M%S"),
'last_date': last_date.strftime("%Y-%m-%d %H:%M:%S %Z"),
'object_id': site.pk,
}

View File

@ -133,7 +133,7 @@ function install_requirements () {
xvfb \
ca-certificates"
PIP="django==1.7 \
PIP="django==1.7.1 \
django-celery-email==1.0.4 \
django-fluent-dashboard==0.3.5 \
https://bitbucket.org/izi/django-admin-tools/get/a0abfffd76a0.zip \