import logging import os import django.contrib.auth.models as amodels import rrdtool from django.conf import settings from django.db import models log = logging.getLogger(__name__) class ModelWithPerms(models.Model): users_read = models.ManyToManyField( amodels.User, related_name="%(class)s_read" ) users_write = models.ManyToManyField( amodels.User, related_name="%(class)s_write" ) groups_read = models.ManyToManyField( amodels.Group, related_name="%(class)s_read" ) groups_write = models.ManyToManyField( amodels.Group, related_name="%(class)s_write" ) class Meta: abstract = True class DataSource(ModelWithPerms): # an mqtt topic can be as long as 65,535 bytes when UTF-8 encoded, # which is probably too much for a sensible db topic = models.CharField(max_length=512) path = models.FilePathField( path=settings.RRD_DB_PATH.as_posix(), recursive=True, max_length=512, ) rrd_config = models.TextField( default=settings.RRD_DS_CONFIG ) active = models.BooleanField( default=True, ) def __str__(self): return self.topic @property def lastupdate(self): try: last = rrdtool.lastupdate(os.path.join( settings.RRD_DB_PATH, self.path )) except rrdtool.OperationalError as e: log.warning("Failure reading from ds: %s", e) return (None, None) else: return last["date"], last["ds"][self.topic.split("/")[-1]] def update(self, ts, value): rrd_path = os.path.join(settings.RRD_DB_PATH, self.path) if not os.path.isfile(rrd_path): rrdtool.create( os.path.join(settings.RRD_DB_PATH, self.path), "--no-overwrite", self.rrd_config.format( ds_name=self.topic.split("/")[-1] ).strip().split('\n'), ) try: rrdtool.update( os.path.join(settings.RRD_DB_PATH, self.path), str(ts) + ":" + str(value) ) except ValueError as e: log.warning("Could not update ds: %s", e) class Graph(ModelWithPerms): title = models.CharField(max_length=64) data_sources = models.ManyToManyField(DataSource) path = models.FilePathField( path=settings.RRD_GRAPH_PATH.as_posix(), recursive=True, max_length=512, ) rrd_config = models.TextField() def __str__(self): return self.title class Dashboard(ModelWithPerms): title = models.CharField(max_length=64) graphs = models.ManyToManyField(Graph) data_sources = models.ManyToManyField(DataSource) template = models.TextField() def __str__(self): return self.title