diff options
Diffstat (limited to 'src/lib/Bcfg2/Reporting/models.py')
-rw-r--r-- | src/lib/Bcfg2/Reporting/models.py | 66 |
1 files changed, 48 insertions, 18 deletions
diff --git a/src/lib/Bcfg2/Reporting/models.py b/src/lib/Bcfg2/Reporting/models.py index 4be509f53..598e1c6ec 100644 --- a/src/lib/Bcfg2/Reporting/models.py +++ b/src/lib/Bcfg2/Reporting/models.py @@ -3,7 +3,7 @@ import sys from django.core.exceptions import ImproperlyConfigured try: - from django.db import models + from django.db import models, backend, connection except ImproperlyConfigured: e = sys.exc_info()[1] print("Reports: unable to import django models: %s" % e) @@ -26,6 +26,8 @@ TYPE_CHOICES = ( (TYPE_EXTRA, 'Extra'), ) +_our_backend = None + def convert_entry_type_to_id(type_name): """Convert a entry type to its entry id""" @@ -49,6 +51,22 @@ def hash_entry(entry_dict): return hash(cPickle.dumps(dataset)) +def _quote(value): + """ + Quote a string to use as a table name or column + + Newer versions and various drivers require an argument + https://code.djangoproject.com/ticket/13630 + """ + global _our_backend + if not _our_backend: + try: + _our_backend = backend.DatabaseOperations(connection) + except TypeError: + _our_backend = backend.DatabaseOperations() + return _our_backend.quote_name(value) + + class Client(models.Model): """Object representing every client we have seen stats for.""" creation = models.DateTimeField(auto_now_add=True) @@ -77,16 +95,20 @@ class InteractionManager(models.Manager): cursor = connection.cursor() cfilter = "expiration is null" - sql = 'select ri.id, x.client_id from (select client_id, MAX(timestamp) ' + \ - 'as timer from Reporting_interaction' + sql = 'select ri.id, x.client_id from ' + \ + '(select client_id, MAX(timestamp) as timer from ' + \ + _quote('Reporting_interaction') if maxdate: if not isinstance(maxdate, datetime): raise ValueError('Expected a datetime object') sql = sql + " where timestamp <= '%s' " % maxdate cfilter = "(expiration is null or expiration > '%s') and creation <= '%s'" % (maxdate, maxdate) - sql = sql + ' GROUP BY client_id) x, Reporting_interaction ri where ' + \ - 'ri.client_id = x.client_id AND ri.timestamp = x.timer' - sql = sql + " and x.client_id in (select id from Reporting_client where %s)" % cfilter + sql = sql + ' GROUP BY client_id) x, ' + \ + _quote('Reporting_interaction') + \ + ' ri where ri.client_id = x.client_id AND' + \ + ' ri.timestamp = x.timer and x.client_id in' + \ + ' (select id from %s where %s)' % \ + (_quote('Reporting_client'), cfilter) try: cursor.execute(sql) return [item[0] for item in cursor.fetchall()] @@ -95,7 +117,6 @@ class InteractionManager(models.Manager): pass return [] - def recent(self, maxdate=None): """ Returns the most recent interactions for clients as of a date @@ -115,7 +136,7 @@ class Interaction(models.Model): timestamp = models.DateTimeField(db_index=True) # Timestamp for this record state = models.CharField(max_length=32) # good/bad/modified/etc repo_rev_code = models.CharField(max_length=64) # repo revision at time of interaction - server = models.CharField(max_length=256) # Name of the server used for the interaction + server = models.CharField(max_length=256) # server used for interaction good_count = models.IntegerField() # of good config-items total_count = models.IntegerField() # of total config-items bad_count = models.IntegerField(default=0) @@ -139,9 +160,11 @@ class Interaction(models.Model): posixgroups = models.ManyToManyField("POSIXGroupEntry") failures = models.ManyToManyField("FailureEntry") - entry_types = ('actions', 'packages', 'paths', 'services', 'sebooleans', - 'seports', 'sefcontexts', 'senodes', 'selogins', 'seusers', - 'seinterfaces', 'sepermissives', 'semodules', 'posixusers', + entry_types = ('actions', 'failures', 'packages', + 'paths', 'services', 'sebooleans', + 'seports', 'sefcontexts', 'senodes', + 'selogins', 'seusers', 'seinterfaces', + 'sepermissives', 'semodules', 'posixusers', 'posixgroups') # Formerly InteractionMetadata @@ -209,18 +232,24 @@ class Interaction(models.Model): def bad(self): rv = [] for entry in self.entry_types: + if entry == 'failures': + continue rv.extend(getattr(self, entry).filter(state=TYPE_BAD)) return rv def modified(self): rv = [] for entry in self.entry_types: + if entry == 'failures': + continue rv.extend(getattr(self, entry).filter(state=TYPE_MODIFIED)) return rv def extra(self): rv = [] for entry in self.entry_types: + if entry == 'failures': + continue rv.extend(getattr(self, entry).filter(state=TYPE_EXTRA)) return rv @@ -232,7 +261,8 @@ class Interaction(models.Model): class Performance(models.Model): """Object representing performance data for any interaction.""" - interaction = models.ForeignKey(Interaction, related_name="performance_items") + interaction = models.ForeignKey(Interaction, + related_name="performance_items") metric = models.CharField(max_length=128) value = models.DecimalField(max_digits=32, decimal_places=16) @@ -265,11 +295,11 @@ class Group(models.Model): class Meta: ordering = ('name',) - @staticmethod def prune_orphans(): '''Prune unused groups''' - Group.objects.filter(interaction__isnull=True, group__isnull=True).delete() + Group.objects.filter(interaction__isnull=True, + group__isnull=True).delete() class Bundle(models.Model): @@ -287,11 +317,11 @@ class Bundle(models.Model): class Meta: ordering = ('name',) - @staticmethod def prune_orphans(): '''Prune unused bundles''' - Bundle.objects.filter(interaction__isnull=True, group__isnull=True).delete() + Bundle.objects.filter(interaction__isnull=True, + group__isnull=True).delete() # new interaction models @@ -394,7 +424,7 @@ class BaseEntry(models.Model): def prune_orphans(cls): '''Remove unused entries''' # yeat another sqlite hack - cls_orphans = [x['id'] \ + cls_orphans = [x['id'] for x in cls.objects.filter(interaction__isnull=True).values("id")] i = 0 while i < len(cls_orphans): @@ -669,7 +699,7 @@ class PathEntry(SuccessEntry): acls = models.ManyToManyField(FileAcl) detail_type = models.IntegerField(default=0, - choices=DETAIL_CHOICES) + choices=DETAIL_CHOICES) details = models.TextField(default='') ENTRY_TYPE = r"Path" |