Fixes on resources
This commit is contained in:
parent
3b4b69e9a2
commit
d3727f0565
5
TODO.md
5
TODO.md
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -12,12 +12,11 @@ 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)
|
||||
mark_as_unread, mark_as_read, set_default_queue)
|
||||
from .filters import MyTicketsListFilter, TicketStateListFilter
|
||||
from .forms import MessageInlineForm, TicketForm
|
||||
from .helpers import get_ticket_changes, markdown_formated_changes, filter_actions
|
||||
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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,7 +43,8 @@ class ListCreationForm(CleanAddressMixin, forms.ModelForm):
|
|||
|
||||
def save(self, commit=True):
|
||||
obj = super(ListCreationForm, self).save(commit=commit)
|
||||
obj.set_password(self.cleaned_data["password1"])
|
||||
if not orchestra_settings.ORCHESTRA_MIGRATION_MODE:
|
||||
obj.set_password(self.cleaned_data["password1"])
|
||||
return obj
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -8,7 +8,6 @@ from orchestra.core import services
|
|||
|
||||
from . import validators, settings
|
||||
|
||||
# TODO rename app to mailboxes
|
||||
|
||||
class Mailbox(models.Model):
|
||||
CUSTOM = 'CUSTOM'
|
||||
|
|
|
@ -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')
|
||||
|
||||
|
||||
|
|
21
orchestra/apps/resources/actions.py
Normal file
21
orchestra/apps/resources/actions.py
Normal 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'
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
@ -159,6 +160,9 @@ class ResourceData(models.Model):
|
|||
self.used = current or 0
|
||||
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):
|
||||
|
@ -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()
|
||||
|
@ -178,6 +182,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():
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
value = getattr(service, field)
|
||||
field = field.replace('_id', '')
|
||||
if field in fk_fields:
|
||||
value = getattr(service, field + '_id')
|
||||
else:
|
||||
value = getattr(service, field)
|
||||
query.append('%s=%s' % (field, value))
|
||||
opts = service._meta
|
||||
url = reverse('admin:%s_%s_add' % (opts.app_label, opts.model_name))
|
||||
|
|
|
@ -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=(
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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 \
|
||||
|
|
Loading…
Reference in a new issue