Fixes on resource monitoring

This commit is contained in:
Marc 2014-07-11 22:08:16 +00:00
parent 5344e732fc
commit bc398644b7
3 changed files with 79 additions and 68 deletions

View File

@ -0,0 +1,68 @@
import datetime
from django.contrib.contenttypes.models import ContentType
from django.db.models.loading import get_model
from django.utils import timezone
from orchestra.models.utils import get_model_field_path
from .backends import ServiceMonitor
def get_used_resource(data):
""" Computes MonitorData.used based on related monitors """
MonitorData = type(data)
resource = data.resource
today = timezone.now()
result = 0
has_result = False
for monitor in resource.monitors:
# Get related dataset
resource_model = data.content_type.model_class()
monitor_model = get_model(ServiceMonitor.get_backend(monitor).model)
if resource_model == monitor_model:
dataset = MonitorData.objects.filter(monitor=monitor,
content_type=data.content_type_id, object_id=data.object_id)
else:
path = get_model_field_path(monitor_model, resource_model)
fields = '__'.join(path)
objects = monitor_model.objects.filter(**{fields: data.object_id})
pks = objects.values_list('id', flat=True)
ct = ContentType.objects.get_for_model(monitor_model)
dataset = MonitorData.objects.filter(monitor=monitor,
content_type=ct, object_id__in=pks)
# Process dataset according to resource.period
if resource.period == resource.MONTHLY_AVG:
try:
last = dataset.latest()
except MonitorData.DoesNotExist:
continue
has_result = True
epoch = datetime(year=today.year, month=today.month, day=1,
tzinfo=timezone.utc)
total = (epoch-last.date).total_seconds()
dataset = dataset.filter(date__year=today.year,
date__month=today.month)
for data in dataset:
slot = (previous-data.date).total_seconds()
result += data.value * slot/total
elif resource.period == resource.MONTHLY_SUM:
dataset = dataset.filter(date__year=today.year, date__month=today.month)
# FIXME Aggregation of 0s returns None! django bug?
# value = dataset.aggregate(models.Sum('value'))['value__sum']
values = dataset.values_list('value', flat=True)
if values:
has_result = True
result += sum(values)
elif resource.period == resource.LAST:
try:
result += dataset.latest().value
except MonitorData.DoesNotExist:
continue
has_result = True
else:
msg = "%s support not implemented" % data.period
raise NotImplementedError(msg)
return result if has_result else None

View File

@ -1,18 +1,13 @@
import datetime
from django.db import models
from django.db.models.loading import get_model
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core import validators from django.core import validators
from django.utils import timezone from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from djcelery.models import PeriodicTask, CrontabSchedule from djcelery.models import PeriodicTask, CrontabSchedule
from orchestra.models.fields import MultiSelectField from orchestra.models.fields import MultiSelectField
from orchestra.models.utils import get_model_field_path
from orchestra.utils.apps import autodiscover
from . import helpers
from .backends import ServiceMonitor from .backends import ServiceMonitor
@ -131,56 +126,7 @@ class ResourceData(models.Model):
allocated=resource.default_allocation) allocated=resource.default_allocation)
def get_used(self): def get_used(self):
resource = self.resource return helpers.get_used(self)
today = timezone.now()
result = 0
has_result = False
for monitor in resource.monitors:
resource_model = self.content_type.model_class()
monitor_model = get_model(ServiceMonitor.get_backend(monitor).model)
if resource_model == monitor_model:
dataset = MonitorData.objects.filter(monitor=monitor,
content_type=self.content_type_id, object_id=self.object_id)
else:
path = get_model_field_path(monitor_model, resource_model)
fields = '__'.join(path)
objects = monitor_model.objects.filter(**{fields: self.object_id})
pks = objects.values_list('id', flat=True)
ct = ContentType.objects.get_for_model(monitor_model)
dataset = MonitorData.objects.filter(monitor=monitor,
content_type=ct, object_id__in=pks)
if resource.period == resource.MONTHLY_AVG:
try:
last = dataset.latest()
except MonitorData.DoesNotExist:
continue
has_result = True
epoch = datetime(year=today.year, month=today.month, day=1,
tzinfo=timezone.utc)
total = (epoch-last.date).total_seconds()
dataset = dataset.filter(date__year=today.year,
date__month=today.month)
for data in dataset:
slot = (previous-data.date).total_seconds()
result += data.value * slot/total
elif resource.period == resource.MONTHLY_SUM:
data = dataset.filter(date__year=today.year, date__month=today.month)
# FIXME Aggregation of 0s returns None! django bug?
# value = data.aggregate(models.Sum('value'))['value__sum']
values = data.values_list('value', flat=True)
if values:
has_result = True
result += sum(values)
elif resource.period == resource.LAST:
try:
result += dataset.latest().value
except MonitorData.DoesNotExist:
continue
has_result = True
else:
msg = "%s support not implemented" % self.period
raise NotImplementedError(msg)
return result if has_result else None
class MonitorData(models.Model): class MonitorData(models.Model):

View File

@ -4,7 +4,6 @@ from django.utils import importlib
def get_model(label, import_module=True): def get_model(label, import_module=True):
""" returns the modeladmin registred for model """
app_label, model_name = label.split('.') app_label, model_name = label.split('.')
model = loading.get_model(app_label, model_name) model = loading.get_model(app_label, model_name)
if model is None: if model is None:
@ -43,21 +42,20 @@ def get_field_value(obj, field_name):
try: try:
rel = getattr(rel, name) rel = getattr(rel, name)
except AttributeError: except AttributeError:
# maybe it is a query manager # maybe is a query manager
rel = getattr(rel.get(), name) rel = getattr(rel.get(), name)
return rel return rel
def get_model_field_path(origin, target): def get_model_field_path(origin, target):
""" BFS search on model relaion fields """ """ BFS search on model relaion fields """
mqueue = [] queue = []
mqueue.append([origin]) queue.append(([origin], []))
pqueue = [[]] while queue:
while mqueue: model, path = queue.pop(0)
model = mqueue.pop(0)
path = pqueue.pop(0)
if len(model) > 4: if len(model) > 4:
raise RuntimeError('maximum recursion depth exceeded while looking for %s" % target') msg = "maximum recursion depth exceeded while looking for %s"
raise RuntimeError(msg % target)
node = model[-1] node = model[-1]
if node == target: if node == target:
return path return path
@ -65,7 +63,6 @@ def get_model_field_path(origin, target):
if field.rel: if field.rel:
new_model = list(model) new_model = list(model)
new_model.append(field.rel.to) new_model.append(field.rel.to)
mqueue.append(new_model)
new_path = list(path) new_path = list(path)
new_path.append(field.name) new_path.append(field.name)
pqueue.append(new_path) queue.append((new_model, new_path))