Fixes on resource monitoring
This commit is contained in:
parent
5344e732fc
commit
bc398644b7
|
@ -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
|
|
@ -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):
|
||||||
|
|
|
@ -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))
|
||||||
|
|
Loading…
Reference in New Issue