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.models import ContentType
from django.core import validators
from django.utils import timezone
from django.db import models
from django.utils.translation import ugettext_lazy as _
from djcelery.models import PeriodicTask, CrontabSchedule
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
@ -131,56 +126,7 @@ class ResourceData(models.Model):
allocated=resource.default_allocation)
def get_used(self):
resource = self.resource
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
return helpers.get_used(self)
class MonitorData(models.Model):

View File

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