Added support for resource monitoring on admin
This commit is contained in:
parent
917b0b9329
commit
be00ab533c
9
TODO.md
9
TODO.md
|
@ -182,19 +182,10 @@ Remember that, as always with QuerySets, any subsequent chained methods which im
|
||||||
|
|
||||||
* BackendLog.updated_at (tasks that run over several minutes when finished they do not appear first on the changelist) (like celery tasks.when)
|
* BackendLog.updated_at (tasks that run over several minutes when finished they do not appear first on the changelist) (like celery tasks.when)
|
||||||
|
|
||||||
|
|
||||||
* rename admin prefetch_related to list_prefetch_related for consistency
|
|
||||||
|
|
||||||
|
|
||||||
* LAST resource monitor option -> SUM(last backend)
|
|
||||||
|
|
||||||
* Resource.monitor(async=True) admin action
|
* Resource.monitor(async=True) admin action
|
||||||
|
|
||||||
* Validate a model path exists between resource.content_type and backend.model
|
* Validate a model path exists between resource.content_type and backend.model
|
||||||
|
|
||||||
* Add support for whitelisted IPs on traffic monitoring ['127.0.0.1',]
|
|
||||||
|
|
||||||
|
|
||||||
* Periodic task for cleaning old monitoring data
|
* Periodic task for cleaning old monitoring data
|
||||||
|
|
||||||
* Generate reports of Account contracted services
|
* Generate reports of Account contracted services
|
||||||
|
|
|
@ -95,7 +95,7 @@ class ChangeViewActionsMixin(object):
|
||||||
return views
|
return views
|
||||||
|
|
||||||
def change_view(self, request, object_id, **kwargs):
|
def change_view(self, request, object_id, **kwargs):
|
||||||
if not 'extra_context' in kwargs:
|
if kwargs.get('extra_context', None) is None:
|
||||||
kwargs['extra_context'] = {}
|
kwargs['extra_context'] = {}
|
||||||
obj = self.get_object(request, unquote(object_id))
|
obj = self.get_object(request, unquote(object_id))
|
||||||
kwargs['extra_context']['object_tools_items'] = [
|
kwargs['extra_context']['object_tools_items'] = [
|
||||||
|
@ -153,12 +153,12 @@ class ChangeAddFieldsMixin(object):
|
||||||
|
|
||||||
|
|
||||||
class ExtendedModelAdmin(ChangeViewActionsMixin, ChangeAddFieldsMixin, admin.ModelAdmin):
|
class ExtendedModelAdmin(ChangeViewActionsMixin, ChangeAddFieldsMixin, admin.ModelAdmin):
|
||||||
prefetch_related = None
|
list_prefetch_related = None
|
||||||
|
|
||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
qs = super(ExtendedModelAdmin, self).get_queryset(request)
|
qs = super(ExtendedModelAdmin, self).get_queryset(request)
|
||||||
if self.prefetch_related:
|
if self.list_prefetch_related:
|
||||||
qs = qs.prefetch_related(*self.prefetch_related)
|
qs = qs.prefetch_related(*self.list_prefetch_related)
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ class DatabaseAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
readonly_fields = ('account_link', 'display_users',)
|
readonly_fields = ('account_link', 'display_users',)
|
||||||
filter_horizontal = ['users']
|
filter_horizontal = ['users']
|
||||||
filter_by_account_fields = ('users',)
|
filter_by_account_fields = ('users',)
|
||||||
prefetch_related = ('users',)
|
list_prefetch_related = ('users',)
|
||||||
|
|
||||||
def display_users(self, db):
|
def display_users(self, db):
|
||||||
links = []
|
links = []
|
||||||
|
@ -90,7 +90,7 @@ class DatabaseUserAdmin(SelectAccountAdminMixin, ChangePasswordAdminMixin, Exten
|
||||||
)
|
)
|
||||||
readonly_fields = ('account_link', 'display_databases',)
|
readonly_fields = ('account_link', 'display_databases',)
|
||||||
filter_by_account_fields = ('databases',)
|
filter_by_account_fields = ('databases',)
|
||||||
prefetch_related = ('databases',)
|
list_prefetch_related = ('databases',)
|
||||||
|
|
||||||
def display_databases(self, user):
|
def display_databases(self, user):
|
||||||
links = []
|
links = []
|
||||||
|
|
|
@ -60,7 +60,7 @@ class MailboxAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedMo
|
||||||
change_readonly_fields = ('name',)
|
change_readonly_fields = ('name',)
|
||||||
add_form = MailboxCreationForm
|
add_form = MailboxCreationForm
|
||||||
form = MailboxChangeForm
|
form = MailboxChangeForm
|
||||||
prefetch_related = ('addresses__domain',)
|
list_prefetch_related = ('addresses__domain',)
|
||||||
|
|
||||||
def display_addresses(self, mailbox):
|
def display_addresses(self, mailbox):
|
||||||
addresses = []
|
addresses = []
|
||||||
|
@ -106,7 +106,7 @@ class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
filter_by_account_fields = ('domain', 'mailboxes')
|
filter_by_account_fields = ('domain', 'mailboxes')
|
||||||
filter_horizontal = ['mailboxes']
|
filter_horizontal = ['mailboxes']
|
||||||
form = AddressForm
|
form = AddressForm
|
||||||
prefetch_related = ('mailboxes', 'domain')
|
list_prefetch_related = ('mailboxes', 'domain')
|
||||||
|
|
||||||
domain_link = admin_link('domain', order='domain__name')
|
domain_link = admin_link('domain', order='domain__name')
|
||||||
|
|
||||||
|
|
|
@ -4,18 +4,29 @@ from django.shortcuts import redirect
|
||||||
from django.utils.translation import ungettext, ugettext_lazy as _
|
from django.utils.translation import ungettext, ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
@transaction.atomic
|
|
||||||
def run_monitor(modeladmin, request, queryset):
|
def run_monitor(modeladmin, request, queryset):
|
||||||
|
""" Resource and ResourceData run monitors """
|
||||||
|
referer = request.META.get('HTTP_REFERER')
|
||||||
|
if not queryset:
|
||||||
|
modeladmin.message_user(request, _("No resource has been selected,"))
|
||||||
|
return redirect(referer)
|
||||||
for resource in queryset:
|
for resource in queryset:
|
||||||
resource.monitor()
|
resource.monitor()
|
||||||
modeladmin.log_change(request, resource, _("Run monitors"))
|
modeladmin.log_change(request, resource, _("Run monitors"))
|
||||||
num = len(queryset)
|
num = len(queryset)
|
||||||
|
async = resource.monitor.func_defaults[0]
|
||||||
|
if async:
|
||||||
|
# TODO schedulet link to celery taskstate page
|
||||||
|
msg = ungettext(
|
||||||
|
_("One selected resource has been scheduled for monitoring."),
|
||||||
|
_("%s selected resource have been scheduled for monitoring.") % num,
|
||||||
|
num)
|
||||||
|
else:
|
||||||
msg = ungettext(
|
msg = ungettext(
|
||||||
_("One selected resource has been monitored."),
|
_("One selected resource has been monitored."),
|
||||||
_("%s selected resource have been monitored.") % num,
|
_("%s selected resource have been monitored.") % num,
|
||||||
num)
|
num)
|
||||||
modeladmin.message_user(request, msg)
|
modeladmin.message_user(request, msg)
|
||||||
referer = request.META.get('HTTP_REFERER')
|
|
||||||
if referer:
|
if referer:
|
||||||
return redirect(referer)
|
return redirect(referer)
|
||||||
run_monitor.url_name = 'monitor'
|
run_monitor.url_name = 'monitor'
|
||||||
|
|
|
@ -40,6 +40,8 @@ class ResourceAdmin(ExtendedModelAdmin):
|
||||||
'fields': ('monitors', 'crontab'),
|
'fields': ('monitors', 'crontab'),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
actions = (run_monitor,)
|
||||||
|
change_view_actions = actions
|
||||||
change_readonly_fields = ('name', 'content_type')
|
change_readonly_fields = ('name', 'content_type')
|
||||||
prepopulated_fields = {'name': ('verbose_name',)}
|
prepopulated_fields = {'name': ('verbose_name',)}
|
||||||
|
|
||||||
|
@ -60,7 +62,8 @@ class ResourceAdmin(ExtendedModelAdmin):
|
||||||
) % {
|
) % {
|
||||||
'not_routed': ', '.join(not_routed)
|
'not_routed': ', '.join(not_routed)
|
||||||
})
|
})
|
||||||
return super(ResourceAdmin, self).changeform_view(request, object_id, form_url, extra_context)
|
return super(ResourceAdmin, self).change_view(request, object_id, form_url=form_url,
|
||||||
|
extra_context=extra_context)
|
||||||
|
|
||||||
def save_model(self, request, obj, form, change):
|
def save_model(self, request, obj, form, change):
|
||||||
super(ResourceAdmin, self).save_model(request, obj, form, change)
|
super(ResourceAdmin, self).save_model(request, obj, form, change)
|
||||||
|
@ -98,7 +101,7 @@ class ResourceDataAdmin(ExtendedModelAdmin):
|
||||||
change_view_actions = actions
|
change_view_actions = actions
|
||||||
ordering = ('-updated_at',)
|
ordering = ('-updated_at',)
|
||||||
list_select_related = ('resource__content_type',)
|
list_select_related = ('resource__content_type',)
|
||||||
prefetch_related = ('content_object',)
|
list_prefetch_related = ('content_object',)
|
||||||
|
|
||||||
resource_link = admin_link('resource')
|
resource_link = admin_link('resource')
|
||||||
content_object_link = admin_link('content_object')
|
content_object_link = admin_link('content_object')
|
||||||
|
|
|
@ -29,7 +29,7 @@ def compute_resource_usage(data):
|
||||||
has_result = True
|
has_result = True
|
||||||
result += sum(values)
|
result += sum(values)
|
||||||
elif resource.period == resource.LAST:
|
elif resource.period == resource.LAST:
|
||||||
result = dataset.value
|
result += dataset.value
|
||||||
has_result = True
|
has_result = True
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError("%s support not implemented" % data.period)
|
raise NotImplementedError("%s support not implemented" % data.period)
|
||||||
|
|
|
@ -127,6 +127,11 @@ class Resource(models.Model):
|
||||||
def get_verbose_name(self):
|
def get_verbose_name(self):
|
||||||
return self.verbose_name or self.name
|
return self.verbose_name or self.name
|
||||||
|
|
||||||
|
def monitor(self, async=True):
|
||||||
|
if async:
|
||||||
|
return tasks.monitor.delay(self.pk, async=async)
|
||||||
|
tasks.monitor(self.pk, async=async)
|
||||||
|
|
||||||
|
|
||||||
class ResourceData(models.Model):
|
class ResourceData(models.Model):
|
||||||
""" Stores computed resource usage and allocation """
|
""" Stores computed resource usage and allocation """
|
||||||
|
@ -174,8 +179,11 @@ class ResourceData(models.Model):
|
||||||
self.updated_at = timezone.now()
|
self.updated_at = timezone.now()
|
||||||
self.save(update_fields=['used', 'updated_at'])
|
self.save(update_fields=['used', 'updated_at'])
|
||||||
|
|
||||||
def monitor(self):
|
def monitor(self, async=False):
|
||||||
tasks.monitor(self.resource_id, ids=(self.object_id,))
|
ids = (self.object_id,)
|
||||||
|
if async:
|
||||||
|
return tasks.monitor.delay(self.resource_id, ids=ids, async=async)
|
||||||
|
return tasks.monitor(self.resource_id, ids=ids, async=async)
|
||||||
|
|
||||||
def get_monitor_datasets(self):
|
def get_monitor_datasets(self):
|
||||||
resource = self.resource
|
resource = self.resource
|
||||||
|
|
|
@ -7,7 +7,7 @@ from .backends import ServiceMonitor
|
||||||
|
|
||||||
|
|
||||||
@shared_task(name='resources.Monitor')
|
@shared_task(name='resources.Monitor')
|
||||||
def monitor(resource_id, ids=None):
|
def monitor(resource_id, ids=None, async=True):
|
||||||
from .models import ResourceData, Resource
|
from .models import ResourceData, Resource
|
||||||
|
|
||||||
resource = Resource.objects.get(pk=resource_id)
|
resource = Resource.objects.get(pk=resource_id)
|
||||||
|
@ -28,7 +28,7 @@ def monitor(resource_id, ids=None):
|
||||||
for obj in model.objects.filter(**kwargs):
|
for obj in model.objects.filter(**kwargs):
|
||||||
operations.append(Operation.create(backend, obj, Operation.MONITOR))
|
operations.append(Operation.create(backend, obj, Operation.MONITOR))
|
||||||
# TODO async=TRue only when running with celery
|
# TODO async=TRue only when running with celery
|
||||||
Operation.execute(operations, async=True)
|
Operation.execute(operations, async=async)
|
||||||
|
|
||||||
kwargs = {'id__in': ids} if ids else {}
|
kwargs = {'id__in': ids} if ids else {}
|
||||||
# Update used resources and trigger resource exceeded and revovery
|
# Update used resources and trigger resource exceeded and revovery
|
||||||
|
|
|
@ -45,7 +45,7 @@ class WebAppAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
inlines = [WebAppOptionInline]
|
inlines = [WebAppOptionInline]
|
||||||
readonly_fields = ('account_link',)
|
readonly_fields = ('account_link',)
|
||||||
change_readonly_fields = ('name', 'type')
|
change_readonly_fields = ('name', 'type')
|
||||||
prefetch_related = ('content_set__website',)
|
list_prefetch_related = ('content_set__website',)
|
||||||
|
|
||||||
TYPE_HELP_TEXT = {
|
TYPE_HELP_TEXT = {
|
||||||
k: str(unicode(v.get('help_text', '')))
|
k: str(unicode(v.get('help_text', '')))
|
||||||
|
|
|
@ -66,7 +66,7 @@ class WebsiteAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
filter_by_account_fields = ['domains']
|
filter_by_account_fields = ['domains']
|
||||||
prefetch_related = ('domains', 'content_set__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):
|
||||||
|
|
|
@ -87,4 +87,4 @@ WEBSITES_WEBSITE_WWW_LOG_PATH = getattr(settings, 'WEBSITES_WEBSITE_WWW_LOG_PATH
|
||||||
|
|
||||||
|
|
||||||
WEBSITES_TRAFFIC_IGNORE_HOSTS = getattr(settings, 'WEBSITES_TRAFFIC_IGNORE_HOSTS',
|
WEBSITES_TRAFFIC_IGNORE_HOSTS = getattr(settings, 'WEBSITES_TRAFFIC_IGNORE_HOSTS',
|
||||||
[])
|
('127.0.0.1',))
|
||||||
|
|
Loading…
Reference in New Issue