171 lines
5.5 KiB
Python
171 lines
5.5 KiB
Python
import copy
|
|
import datetime
|
|
import decimal
|
|
|
|
from dateutil.relativedelta import relativedelta
|
|
from django.utils import timezone
|
|
from django.utils.translation import ugettext_lazy as _
|
|
|
|
from orchestra import plugins
|
|
|
|
|
|
class Aggregation(plugins.Plugin, metaclass=plugins.PluginMount):
|
|
""" filters and computes dataset usage """
|
|
def filter(self, dataset):
|
|
""" Filter the dataset to get the relevant data according to the period """
|
|
raise NotImplementedError
|
|
|
|
def historic_filter(self, dataset):
|
|
""" Generates (date, dataset) tuples for resource data history reporting """
|
|
raise NotImplementedError
|
|
|
|
def compute_usage(self, dataset):
|
|
""" given a dataset computes its usage according to the method (avg, sum, ...) """
|
|
raise NotImplementedError
|
|
|
|
def compute_historic_usage(self, dataset):
|
|
""" generates [(data, usage),] tuples for resource data history reporting """
|
|
raise NotImplementedError
|
|
|
|
|
|
class Last(Aggregation):
|
|
""" Sum of the last value of all monitors """
|
|
name = 'last'
|
|
verbose_name = _("Last value")
|
|
|
|
def filter(self, dataset, date=None):
|
|
dataset = dataset.order_by('object_id', '-id').distinct('monitor')
|
|
if date is not None:
|
|
dataset = dataset.filter(created_at__lte=date)
|
|
return dataset
|
|
|
|
def monthly_historic_filter(self, dataset):
|
|
today = timezone.now().date()
|
|
date = datetime.date(
|
|
year=today.year,
|
|
month=today.month,
|
|
day=1,
|
|
)
|
|
while True:
|
|
dataset_copy = copy.copy(dataset)
|
|
dataset_copy = self.filter(dataset_copy, date=date)
|
|
try:
|
|
dataset_copy[0]
|
|
except IndexError:
|
|
yield (date, None)
|
|
yield (date, dataset_copy)
|
|
date -= relativedelta(months=1)
|
|
|
|
def historic_filter(self, dataset):
|
|
yield (timezone.now().date(), self.filter(dataset))
|
|
yield from self.monthly_historic_filter(dataset)
|
|
|
|
def compute_usage(self, dataset):
|
|
values = dataset.values_list('value', flat=True)
|
|
if values:
|
|
return sum(values)
|
|
return None
|
|
|
|
def compute_historic_usage(self, dataset):
|
|
dataset = dataset.only('object_id', 'value', 'content_object_repr')
|
|
return [(mdata, mdata.value) for mdata in dataset]
|
|
|
|
|
|
class MonthlySum(Last):
|
|
""" Monthly sum the values of all monitors """
|
|
name = 'monthly-sum'
|
|
verbose_name = _("Monthly Sum")
|
|
|
|
def filter(self, dataset, date=None):
|
|
if date is None:
|
|
date = timezone.now().date()
|
|
return dataset.filter(
|
|
created_at__year=date.year,
|
|
created_at__month=date.month,
|
|
)
|
|
|
|
def historic_filter(self, dataset):
|
|
yield from self.monthly_historic_filter(dataset)
|
|
|
|
def compute_historic_usage(self, dataset):
|
|
objects = {}
|
|
mdatas = {}
|
|
for mdata in dataset.only('object_id', 'value', 'content_object_repr'):
|
|
mdatas[mdata.object_id] = mdata
|
|
try:
|
|
objects[mdata.object_id] += mdata.value
|
|
except KeyError:
|
|
objects[mdata.object_id] = mdata.value
|
|
return [(mdatas[object_id], value) for object_id, value in objects.items()]
|
|
|
|
|
|
class MonthlyAvg(MonthlySum):
|
|
""" sum of the monthly averages of each monitor """
|
|
name = 'monthly-avg'
|
|
verbose_name = _("Monthly AVG")
|
|
|
|
def get_epoch(self, date=None):
|
|
if date is None:
|
|
date = timezone.now().date()
|
|
return datetime.date(
|
|
year=date.year,
|
|
month=date.month,
|
|
day=1,
|
|
)
|
|
|
|
def compute_usage(self, dataset, historic=False):
|
|
result = 0
|
|
has_result = False
|
|
aggregate = []
|
|
for object_id, dataset in dataset.order_by('created_at').group_by('object_id').items():
|
|
try:
|
|
last = dataset[-1]
|
|
except IndexError:
|
|
continue
|
|
epoch = self.get_epoch(date=last.created_at)
|
|
total = (last.created_at-epoch).total_seconds()
|
|
ini = epoch
|
|
current = 0
|
|
for mdata in dataset:
|
|
has_result = True
|
|
slot = (mdata.created_at-ini).total_seconds()
|
|
current += mdata.value * decimal.Decimal(str(slot/total))
|
|
ini = mdata.created_at
|
|
if historic:
|
|
aggregate.append(
|
|
(mdata, current)
|
|
)
|
|
else:
|
|
result += current
|
|
if has_result:
|
|
if historic:
|
|
return aggregate
|
|
return result
|
|
return None
|
|
|
|
def compute_historic_usage(self, dataset):
|
|
return self.compute_usage(dataset, historic=True)
|
|
|
|
|
|
class Last10DaysAvg(MonthlyAvg):
|
|
""" sum of the last 10 days averages of each monitor """
|
|
name = 'last-10-days-avg'
|
|
verbose_name = _("Last 10 days AVG")
|
|
days = 10
|
|
|
|
def get_epoch(self, date=None):
|
|
if date is None:
|
|
date = timezone.now().date()
|
|
return date - datetime.timedelta(days=self.days)
|
|
|
|
def filter(self, dataset, date=None):
|
|
epoch = self.get_epoch(date=date)
|
|
dataset = dataset.filter(created_at__gt=epoch)
|
|
if date is not None:
|
|
dataset = dataset.filter(created_at__lte=date)
|
|
return dataset
|
|
|
|
def historic_filter(self, dataset):
|
|
yield (timezone.now().date(), self.filter(dataset))
|
|
yield from super(Last10DaysAvg, self).historic_filter(dataset)
|