Added support for resource monitoring on admin

This commit is contained in:
Marc Aymerich 2014-11-20 16:48:50 +00:00
parent 917b0b9329
commit be00ab533c
12 changed files with 46 additions and 33 deletions

View File

@ -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

View File

@ -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

View File

@ -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 = []

View File

@ -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')

View File

@ -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)
msg = ungettext( async = resource.monitor.func_defaults[0]
_("One selected resource has been monitored."), if async:
_("%s selected resource have been monitored.") % num, # TODO schedulet link to celery taskstate page
num) msg = ungettext(
_("One selected resource has been scheduled for monitoring."),
_("%s selected resource have been scheduled for monitoring.") % num,
num)
else:
msg = ungettext(
_("One selected resource has been monitored."),
_("%s selected resource have been monitored.") % 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'

View File

@ -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')

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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', '')))

View File

@ -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):

View File

@ -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',))