summaryrefslogtreecommitdiffstats
path: root/src/lib/Server/Reports/reports
diff options
context:
space:
mode:
authorJoey Hagedorn <hagedorn@mcs.anl.gov>2006-11-22 21:18:05 +0000
committerJoey Hagedorn <hagedorn@mcs.anl.gov>2006-11-22 21:18:05 +0000
commitc57c79a36f1e4d2b66ef7f01bc0a82ef7d5996e8 (patch)
tree139b14f96b8baa53dc837c0402113475f00b75b4 /src/lib/Server/Reports/reports
parentebf644b4c820244aad5019b5540ddac9401109de (diff)
downloadbcfg2-c57c79a36f1e4d2b66ef7f01bc0a82ef7d5996e8.tar.gz
bcfg2-c57c79a36f1e4d2b66ef7f01bc0a82ef7d5996e8.tar.bz2
bcfg2-c57c79a36f1e4d2b66ef7f01bc0a82ef7d5996e8.zip
finishing move
git-svn-id: https://svn.mcs.anl.gov/repos/bcfg/trunk/bcfg2@2521 ce84e21b-d406-0410-9b95-82705330c041
Diffstat (limited to 'src/lib/Server/Reports/reports')
-rw-r--r--src/lib/Server/Reports/reports/__init__.py0
-rw-r--r--src/lib/Server/Reports/reports/models.py236
-rw-r--r--src/lib/Server/Reports/reports/sql/client.sql1
-rw-r--r--src/lib/Server/Reports/reports/templates/base.html45
-rw-r--r--src/lib/Server/Reports/reports/templates/clients/client-nodebox.html63
-rw-r--r--src/lib/Server/Reports/reports/templates/clients/detail.html14
-rw-r--r--src/lib/Server/Reports/reports/templates/clients/index.html36
-rw-r--r--src/lib/Server/Reports/reports/templates/config_items/index.html77
-rw-r--r--src/lib/Server/Reports/reports/templates/displays/index.html18
-rw-r--r--src/lib/Server/Reports/reports/templates/displays/summary-block-direct-links.html7
-rw-r--r--src/lib/Server/Reports/reports/templates/displays/summary-block.html90
-rw-r--r--src/lib/Server/Reports/reports/templates/displays/summary.html29
-rw-r--r--src/lib/Server/Reports/reports/templates/displays/sys_view.html20
-rw-r--r--src/lib/Server/Reports/reports/templates/displays/timing.html52
-rw-r--r--src/lib/Server/Reports/reports/templates/index.html15
-rw-r--r--src/lib/Server/Reports/reports/templatetags/__init__.py0
-rw-r--r--src/lib/Server/Reports/reports/templatetags/django_templating_sigh.py40
-rw-r--r--src/lib/Server/Reports/reports/views.py255
18 files changed, 998 insertions, 0 deletions
diff --git a/src/lib/Server/Reports/reports/__init__.py b/src/lib/Server/Reports/reports/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/lib/Server/Reports/reports/__init__.py
diff --git a/src/lib/Server/Reports/reports/models.py b/src/lib/Server/Reports/reports/models.py
new file mode 100644
index 000000000..dff68d272
--- /dev/null
+++ b/src/lib/Server/Reports/reports/models.py
@@ -0,0 +1,236 @@
+'''Django models for BCFG reports'''
+from django.db import models
+from datetime import datetime, timedelta
+
+KIND_CHOICES = (
+ #These are the kinds of config elements
+ ('ConfigFile', 'ConfigFile'),
+ ('Package', 'Package'),
+ ('Service', 'Service'),
+ ('SymLink', 'SymLink'),
+ ('Directory', 'Directory'),
+ ('Permissions','Permissions'),
+)
+PING_CHOICES = (
+ #These are possible ping states
+ ('Up (Y)', 'Y'),
+ ('Down (N)', 'N')
+)
+class Client(models.Model):
+ '''object representing every client we have seen stats for'''
+ creation = models.DateTimeField()
+ name = models.CharField(maxlength=128, core=True)
+ current_interaction = models.ForeignKey('Interaction',
+ null=True, blank=True,
+ related_name="parent_client")
+ expiration = models.DateTimeField(blank=True, null=True)
+
+ def __str__(self):
+ return self.name
+
+ class Admin:
+ pass
+
+class Metadata(models.Model):
+ '''insert magical interface to client metadata here'''
+ client = models.ForeignKey(Client)
+ timestamp = models.DateTimeField()
+ def __str__(self):
+ return self.timestamp
+
+class Repository(models.Model):
+ '''insert magical interface to subversioned repository here'''
+ timestamp = models.DateTimeField()
+ def __str__(self):
+ return self.timestamp
+
+class Ping(models.Model):
+ '''represents a ping of a client (sparsely)'''
+ client = models.ForeignKey(Client, related_name="pings")
+ starttime = models.DateTimeField()
+ endtime = models.DateTimeField()
+ status = models.CharField(maxlength=4, choices=PING_CHOICES)#up/down
+
+ class Meta:
+ get_latest_by = 'endtime'
+
+class InteractiveManager(models.Manager):
+ '''manages interactions objects'''
+
+ '''returns most recent interaction as of specified timestamp in format:
+ '2006-01-01 00:00:00' or 'now' or None->'now' '''
+ def interaction_per_client(self, maxdate = None):
+ from django.db import connection
+ cursor = connection.cursor()
+
+ #in order to prevent traceback when zero records are returned.
+ #this could mask some database errors
+ try:
+ if (maxdate == 'now' or maxdate == None):
+ cursor.execute("select reports_interaction.id, x.client_id from (select client_id, MAX(timestamp) "+
+ "as timer from reports_interaction GROUP BY client_id) x, reports_interaction where "+
+ "reports_interaction.client_id = x.client_id AND reports_interaction.timestamp = x.timer")
+ else:
+ cursor.execute("select reports_interaction.id, x.client_id from (select client_id, timestamp, MAX(timestamp) "+
+ "as timer from reports_interaction WHERE timestamp < %s GROUP BY client_id) x, reports_interaction where "+
+ "reports_interaction.client_id = x.client_id AND reports_interaction.timestamp = x.timer",
+ [maxdate])
+ in_idents = [item[0] for item in cursor.fetchall()]
+ except:
+ in_idents = []
+ return self.filter(id__in = in_idents)
+
+
+class Interaction(models.Model):
+ '''Models each reconfiguration operation interaction between client and server'''
+ client = models.ForeignKey(Client, related_name="interactions", core=True)
+ timestamp = models.DateTimeField()#Timestamp for this record
+ state = models.CharField(maxlength=32)#good/bad/modified/etc
+ repo_revision = models.IntegerField()#repo revision at time of interaction
+ client_version = models.CharField(maxlength=32)#Client Version
+ goodcount = models.IntegerField()#of good config-items
+ totalcount = models.IntegerField()#of total config-items
+
+ def __str__(self):
+ return "With " + self.client.name + " @ " + self.timestamp.isoformat()
+
+ def percentgood(self):
+ if not self.totalcount == 0:
+ return (self.goodcount/float(self.totalcount))*100
+ else:
+ return 0
+
+ def percentbad(self):
+ if not self.totalcount == 0:
+ return ((self.totalcount-self.goodcount)/(float(self.totalcount)))*100
+ else:
+ return 0
+
+ def isclean(self):
+ if (self.bad_items.count() == 0 and self.goodcount == self.totalcount):
+ #if (self.state == "good"):
+ return True
+ else:
+ return False
+
+ def isstale(self):
+ if (self == self.client.current_interaction):#Is Mostrecent
+ if(datetime.now()-self.timestamp > timedelta(hours=25) ):
+ return True
+ else:
+ return False
+ else:
+ #Search for subsequent Interaction for this client
+ #Check if it happened more than 25 hrs ago.
+ if (self.client.interactions.filter(timestamp__gt=self.timestamp)
+ .order_by('timestamp')[0].timestamp -
+ self.timestamp > timedelta(hours=25)):
+ return True
+ else:
+ return False
+ def save(self):
+ super(Interaction, self).save() #call the real save...
+ self.client.current_interaction = self.client.interactions.latest()
+ self.client.save()#save again post update
+
+ objects = InteractiveManager()
+
+ class Admin:
+ list_display = ('client', 'timestamp', 'state')
+ list_filter = ['client', 'timestamp']
+ pass
+ class Meta:
+ get_latest_by = 'timestamp'
+
+class Reason(models.Model):
+ '''reason why modified or bad entry did not verify, or changed'''
+ owner = models.TextField(maxlength=128, blank=True)
+ current_owner = models.TextField(maxlength=128, blank=True)
+ group = models.TextField(maxlength=128, blank=True)
+ current_group = models.TextField(maxlength=128, blank=True)
+ perms = models.TextField(maxlength=4, blank=True)#txt fixes typing issue
+ current_perms = models.TextField(maxlength=4, blank=True)
+ status = models.TextField(maxlength=3, blank=True)#on/off/(None)
+ current_status = models.TextField(maxlength=1, blank=True)#on/off/(None)
+ to = models.TextField(maxlength=256, blank=True)
+ current_to = models.TextField(maxlength=256, blank=True)
+ version = models.TextField(maxlength=128, blank=True)
+ current_version = models.TextField(maxlength=128, blank=True)
+ current_exists = models.BooleanField()#False means its missing. Default True
+ current_diff = models.TextField(maxlength=1280, blank=True)
+ def _str_(self):
+ return "Reason"
+
+class Modified(models.Model):
+ '''Modified configuration element'''
+ interactions = models.ManyToManyField(Interaction, related_name="modified_items")
+ name = models.CharField(maxlength=128, core=True)
+ kind = models.CharField(maxlength=16, choices=KIND_CHOICES)
+ critical = models.BooleanField()
+ reason = models.ForeignKey(Reason)
+ def __str__(self):
+ return self.name
+
+class Extra(models.Model):
+ '''Extra configuration element'''
+ interactions = models.ManyToManyField(Interaction, related_name="extra_items")
+ name = models.CharField(maxlength=128, core=True)
+ kind = models.CharField(maxlength=16, choices=KIND_CHOICES)
+ critical = models.BooleanField()
+ reason = models.ForeignKey(Reason)
+ def __str__(self):
+ return self.name
+
+class Bad(models.Model):
+ '''Bad configuration element'''
+ interactions = models.ManyToManyField(Interaction, related_name="bad_items")
+ name = models.CharField(maxlength=128, core=True)
+ kind = models.CharField(maxlength=16, choices=KIND_CHOICES)
+ critical = models.BooleanField()
+ reason = models.ForeignKey(Reason)
+ def __str__(self):
+ return self.name
+
+class PerformanceManager(models.Manager):
+ '''Provides ability to effectively query for performance information
+ It is possible this should move to the view'''
+ #Date format for maxdate: '2006-01-01 00:00:00'
+ def performance_per_client(self, maxdate = None):
+ from django.db import connection
+ cursor = connection.cursor()
+ if (maxdate == 'now' or maxdate == None):
+ cursor.execute("SELECT reports_client.name, reports_performance.metric, reports_performance.value "+
+ "FROM reports_performance, reports_performance_interaction, reports_client WHERE ( "+
+ "reports_client.current_interaction_id = reports_performance_interaction.interaction_id AND "+
+ "reports_performance.id = reports_performance_interaction.performance_id)")
+ else:
+ cursor.execute("select reports_client.name, reports_performance.metric, "+
+ "reports_performance.value from (Select reports_interaction.client_id as client_id, "+
+ "MAX(reports_interaction.timestamp) as timestamp from reports_interaction where "+
+ "timestamp < %s GROUP BY reports_interaction.client_id) x, reports_client, "+
+ "reports_interaction, reports_performance, reports_performance_interaction where "+
+ "reports_client.id = x.client_id AND x.timestamp = reports_interaction.timestamp AND "+
+ "x.client_id = reports_interaction.client_id AND reports_performance.id = "+
+ "reports_performance_interaction.performance_id AND "+
+ "reports_performance_interaction.interaction_id = reports_interaction.id", [maxdate])
+
+ results = {}
+ for row in cursor.fetchall():
+ try:
+ results[row[0]].__setitem__(row[1], row[2])
+ except KeyError:
+ results[row[0]] = {row[1]:row[2]}
+
+ return results
+
+#performance metrics, models a performance-metric-item
+class Performance(models.Model):
+ '''Object representing performance data for any interaction'''
+ interaction = models.ManyToManyField(Interaction, related_name="performance_items")
+ metric = models.CharField(maxlength=128, core=True)
+ value = models.FloatField(max_digits=32, decimal_places=16)
+ def __str__(self):
+ return self.metric
+
+ objects = PerformanceManager()
+
diff --git a/src/lib/Server/Reports/reports/sql/client.sql b/src/lib/Server/Reports/reports/sql/client.sql
new file mode 100644
index 000000000..6ef37a27f
--- /dev/null
+++ b/src/lib/Server/Reports/reports/sql/client.sql
@@ -0,0 +1 @@
+CREATE VIEW reports_current_interactions AS SELECT x.client_id AS client_id, reports_interaction.id AS interaction_id FROM (select client_id, MAX(timestamp) as timer FROM reports_interaction GROUP BY client_id) x, reports_interaction WHERE reports_interaction.client_id = x.client_id AND reports_interaction.timestamp = x.timer \ No newline at end of file
diff --git a/src/lib/Server/Reports/reports/templates/base.html b/src/lib/Server/Reports/reports/templates/base.html
new file mode 100644
index 000000000..1bee97206
--- /dev/null
+++ b/src/lib/Server/Reports/reports/templates/base.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>{% block title %}Bcfg2 Reporting System{% endblock %}</title>
+ <link rel="stylesheet" type="text/css" href="/site_media/boxypastel.css" />
+ <link rel="stylesheet" type="text/css" href="/site_media/base.css" />
+ <script type="text/javascript" src="/site_media/main.js">
+ </script>
+ {% block extra_header_info %}{% endblock %}
+</head>
+
+<body>
+ <div id="header">
+ <div id="branding">
+ <h1>Bcfg2 Reporting System</h1>
+ </div>
+ <div id="user-tools">...Change is Coming...</div>
+ </div>
+ <div id="sidebar">
+ {% block sidebar %}
+ <ul class="sidebar">
+ <li><a href="/" class="sidebar">Home</a></li>
+ <li><a href="/clients/" class="sidebar">Clients</a></li>
+ <li>
+ <a href="/displays/" class="sidebar">Displays</a>
+ <ul class="sidebar-level2">
+ <li><a href="/displays/sys-view/" class="sidebar">System</a></li>
+ <li><a href="/displays/summary/" class="sidebar">Summary</a></li>
+ <li><a href="/displays/timing/" class="sidebar">Timing</a></li>
+ </ul>
+ </li>
+ </ul>
+ {% endblock %}
+ </div>
+
+ <div id="content-main">
+ <div id="container">
+ {% block pagebanner %}{% endblock %}
+ {% block content %}{% endblock %}
+
+ </div>
+ </div>
+</body>
+</html> \ No newline at end of file
diff --git a/src/lib/Server/Reports/reports/templates/clients/client-nodebox.html b/src/lib/Server/Reports/reports/templates/clients/client-nodebox.html
new file mode 100644
index 000000000..dade598cf
--- /dev/null
+++ b/src/lib/Server/Reports/reports/templates/clients/client-nodebox.html
@@ -0,0 +1,63 @@
+{% load django_templating_sigh %}
+{% if client %}
+ <a name="{{client.name}}"></a>
+ <div class="nodebox" name="{{client.name}}">
+ <span class="notebox">Time Ran: {{interaction.timestamp}}</span>
+ <!--<span class="configbox">(-Insert Profile Name Here-)</span>-->
+
+ <table class="invisitable">
+ <tr><td width="43%"><h2>Node: <span class="nodename">
+ <a href="/clients/{{client.name}}/{{interaction.id}}">{{client.name}}</a></span></h2></td>
+ <td width="23%">
+ {% if interaction.repo_revision %}Revision: {{interaction.repo_revision}}{% endif %}
+ </td>
+ <td width="33%"><div class="statusborder">
+ <div class="greenbar" style="width: {{interaction.percentgood}}%;">&nbsp;</div>
+ <div class="redbar" style="width: {{interaction.percentbad}}%;">&nbsp;</div>
+ </div>
+ </td></tr>
+ </table>
+ {% if interaction.isclean %}
+ <div class="clean">
+ <span class="nodelisttitle">Node is clean; Everything has been satisfactorily configured.</span>
+ </div>
+ {% endif %}
+ {% if interaction.isstale %}
+ <div class="warning">
+ <span class="nodelisttitle">This node did not run within the last 24 hours-- it may be out of date.</span>
+ </div>
+ {% endif %}
+ {% if interaction.bad_items.all %}
+ <div class="bad">
+ <span class="nodelisttitle"><a href="javascript:toggleLayer('{{client.name}}-bad');" title="Click to expand" class="commentLink">{{interaction.bad_items.count}}</a> items did not verify and are considered Dirty.<br /></span>
+ <div class="items" id="{{client.name}}-bad"><ul class="plain">
+ {% for bad in interaction.bad_items.all|sortwell %}
+ <li><strong>{{bad.kind}}: </strong><tt><a href="/elements/bad/{{bad.id}}">{{bad.name}}</a></tt></li>
+ {% endfor %}
+ </ul></div>
+ </div>
+ {% endif %}
+ {% if interaction.modified_items.all %}
+ <div class="modified">
+ <span class="nodelisttitle"><a href="javascript:toggleLayer('{{client.name}}-modified');" title="Click to expand" class="commentLink">{{interaction.modified_items.count}}</a> items were modified in the last run.<br /></span>
+ <div class="items" id="{{client.name}}-modified"><ul class="plain">
+ {% for modified in interaction.modified_items.all|sortwell %}
+ <li><strong>{{modified.kind}}: </strong><tt><a href="/elements/modified/{{modified.id}}">{{modified.name}}</a></tt></li>
+ {% endfor %}
+ </ul></div>
+ </div>
+ {% endif %}
+ {% if interaction.extra_items.all %}
+ <div class="extra">
+ <span class="nodelisttitle"><a href="javascript:toggleLayer('{{client.name}}-extra');" title="Click to expand" class="commentLink">{{interaction.extra_items.count}}</a> extra configuration elements on the node.<br /></span>
+ <div class="items" id="{{client.name}}-extra"><ul class="plain">
+ {% for extra in interaction.extra_items.all|sortwell %}
+ <li><strong>{{extra.kind}}: </strong><tt>{{extra.name}}</tt></li>
+ {% endfor %}
+ </ul></div>
+ </div>
+ {% endif %}
+ </div>
+{% else %}
+ <p>No record could be found for this client.</p>
+{% endif %}
diff --git a/src/lib/Server/Reports/reports/templates/clients/detail.html b/src/lib/Server/Reports/reports/templates/clients/detail.html
new file mode 100644
index 000000000..4ac2123c1
--- /dev/null
+++ b/src/lib/Server/Reports/reports/templates/clients/detail.html
@@ -0,0 +1,14 @@
+{% extends "base.html" %}
+
+{% block title %}Info for: {{client.name}}{% endblock %}
+
+{% block content %}
+<b>Select time: </b>
+<select name=quick onChange="MM_jumpMenu('parent',this,0)">
+ {% for i in client.interactions.all %}
+ <option {% ifequal i.id interaction.id %}selected {% endifequal %} value="/clients/{{client.name}}/{{i.id}}/"> {{i.timestamp}}
+ {% endfor %}
+</select>
+
+{% include "clients/client-nodebox.html" %}
+{% endblock %}
diff --git a/src/lib/Server/Reports/reports/templates/clients/index.html b/src/lib/Server/Reports/reports/templates/clients/index.html
new file mode 100644
index 000000000..9870e2942
--- /dev/null
+++ b/src/lib/Server/Reports/reports/templates/clients/index.html
@@ -0,0 +1,36 @@
+{% extends "base.html" %}
+
+{% block title %}Client Index Listing{% endblock %}
+
+{% block pagebanner %}
+ <div class="header">
+ <h1>Clients List</h1>
+ </div>
+ <br/>
+{% endblock %}
+
+{% block content %}
+{% if client_list_a %}
+<table><tr><td align="top">
+ <ul style="list-style-type:none;">
+ {% for client in client_list_a %}
+ <li><div class="{{client.current_interaction.state}}-lineitem">
+ <a href="{{client.name}}/">{{ client.name }}</a>
+ </div></li>
+ {% endfor %}
+ </ul>
+</td><td align="top">
+ <ul style="list-style-type:none;">
+ {% if client_list_b %}
+ {% for client in client_list_b %}
+ <li><div class="{{client.current_interaction.state}}-lineitem">
+ <a href="{{client.name}}/">{{ client.name }}</a>
+ </div></li>
+ {% endfor %}
+ {% endif %}
+ </ul>
+</tr></tab.e>
+{% else %}
+ <p>No client records are available.</p>
+{% endif %}
+{% endblock %}
diff --git a/src/lib/Server/Reports/reports/templates/config_items/index.html b/src/lib/Server/Reports/reports/templates/config_items/index.html
new file mode 100644
index 000000000..952172715
--- /dev/null
+++ b/src/lib/Server/Reports/reports/templates/config_items/index.html
@@ -0,0 +1,77 @@
+{% extends "base.html" %}
+
+{% block extra_header_info %}
+<script type="text/javascript" src="/site_media/CalendarPopup.js"></script>
+<script language="JavaScript">var cal = new CalendarPopup();</script>
+{% endblock%}
+{% block title %}Configuration Element Details{% endblock %}
+
+{% block pagebanner %}
+ <div class="header">
+ <h1>Configuration Element Details</h1>
+ </div>
+ <br/>
+{% endblock %}
+
+{% block content %}
+{% ifequal mod_or_bad "bad" %}
+<div class="bad">
+<h2>Bad {{item.kind}}: {{item.name}}</h2>
+</div>
+{% else %}
+<div class="modified">
+<h2>Modified {{item.kind}}: {{item.name}}</h2>
+</div>
+{% endifequal %}
+<center>
+<table border=1 padding=0 >
+<tr><th>Reason</th><th>Current Status</th><th>Specified in BCFG</th></tr>
+{% if item.reason.current_owner %}
+<tr><td align="right"><b>Owner: </b></td><td>{{item.reason.owner}}</td><td>{{item.reason.current_owner}}</td></tr>
+{% endif %}{% if item.reason.current_group %}
+<tr><td align="right"><b>Group: </b></td><td>{{item.reason.group}}</td><td>{{item.reason.current_group}}</td></tr>
+{% endif %}{% if item.reason.current_perms %}
+<tr><td align="right"><b>Permissions: </b></td><td>{{item.reason.perms}}</td><td>{{item.reason.current_perms}}</td></tr>
+{% endif %}{% if item.reason.current_status %}
+<tr><td align="right"><b>Status: </b></td><td>{{item.reason.status}}</td><td>{{item.reason.current_status}}</td></tr>
+{% endif %}{% if item.reason.current_to %}
+<tr><td align="right"><b>Link Destination: </b></td><td>{{item.reason.to}}</td><td>{{item.reason.current_to}}</td></tr>
+{% endif %}{% if item.reason.current_version %}
+<tr><td align="right"><b>Version: </b></td><td>{{item.reason.version}}</td><td>{{item.reason.current_version}}</td></tr>
+{% endif %}{% if not item.reason.current_exists %}
+<tr><td align="right"><b>Existance: </b></td><td colspan=2>This item does not currently exist on the host but is specified to exist in the configuration.</td></tr>
+{% endif %}{% if item.reason.current_diff %}
+<tr><td align="right"><b>Unified Diff: </b></td><td colspan=2><pre>{{item.reason.current_diff}}</pre></td></tr>
+{% endif %}
+</table></center>
+<hr/>
+<div>
+<span class="mini-date">
+<b>Enter date or use calendar popup: </b>
+<form name="timestamp-select">
+<input type="text" name="date1" value="{{timestamp_date}}" size=10>@
+<input type="text" name="time" value="{{timestamp_time}}" size=8>
+<a href="" onClick="cal.select(document.forms['timestamp-select'].date1,'anchor1','yyyy-MM-dd'); return false;"
+ name="anchor1" ID="anchor1">Calendar</A>
+<input type="button" name="go" value="Go" onClick="location.href='/elements/{{mod_or_bad}}/{{item.id}}/'+document.forms['timestamp-select'].date1.value+'@'+document.forms['timestamp-select'].time.value;" />
+ | <input type="button" name="now" value="Now" onClick="location.href='/elements/{{mod_or_bad}}/{{item.id}}';"/>
+</form>
+</span><br/><br/><br/></div>
+{% if associated_client_list %}
+ <p>The following clients had this problem as of {{timestamp_date}}@{{timestamp_time}}:</p>
+ {% for client in associated_client_list %}
+ <a href="/clients/{{client.name}}">{{client.name}}</a><br/>
+ {% endfor %}
+ <br />
+ <br />
+{% else %}
+ <p>No Clients had this problem at {{timestamp}}</p>
+{% endif %}
+
+
+
+
+
+
+
+{% endblock %}
diff --git a/src/lib/Server/Reports/reports/templates/displays/index.html b/src/lib/Server/Reports/reports/templates/displays/index.html
new file mode 100644
index 000000000..5d1d3bf76
--- /dev/null
+++ b/src/lib/Server/Reports/reports/templates/displays/index.html
@@ -0,0 +1,18 @@
+{% extends "base.html" %}
+
+{% block title %}Display Index Listing{% endblock %}
+{% block pagebanner %}
+ <div class="header">
+ <h1>BCFG Display Index</h1>
+ {% comment %} <span class="notebox">Report Run @ {% now "F j, Y P"%}</span>{% endcomment %}
+ </div>
+ <br/>
+{% endblock %}
+
+{% block content %}
+<ul>
+<li><a href="/displays/sys-view/">System View</a></li>
+<li><a href="/displays/summary/">Summary Only</a></li>
+<li><a href="/displays/timing/">Timing</a></li>
+</ul>
+{% endblock %}
diff --git a/src/lib/Server/Reports/reports/templates/displays/summary-block-direct-links.html b/src/lib/Server/Reports/reports/templates/displays/summary-block-direct-links.html
new file mode 100644
index 000000000..a218e12b6
--- /dev/null
+++ b/src/lib/Server/Reports/reports/templates/displays/summary-block-direct-links.html
@@ -0,0 +1,7 @@
+{% extends "displays/summary-block.html" %}
+{% block linkprefix1 %}/clients/{% endblock %}
+{% block linkprefix2 %}/clients/{% endblock %}
+{% block linkprefix3 %}/clients/{% endblock %}
+{% block linkprefix4 %}/clients/{% endblock %}
+{% block linkprefix5 %}/clients/{% endblock %}
+{% block linkprefix6 %}/clients/{% endblock %} \ No newline at end of file
diff --git a/src/lib/Server/Reports/reports/templates/displays/summary-block.html b/src/lib/Server/Reports/reports/templates/displays/summary-block.html
new file mode 100644
index 000000000..a42176183
--- /dev/null
+++ b/src/lib/Server/Reports/reports/templates/displays/summary-block.html
@@ -0,0 +1,90 @@
+{% load django_templating_sigh %}
+
+ <div class="nodebox">
+ <h2>Summary:</h2>
+ <p class="indented">{{client_list|length }} Nodes were included in your report.</p>
+ {% if clean_client_list %}
+ <div class="clean">
+ <span class="nodelisttitle"><a href="javascript:toggleLayer('goodsummary');" title="Click to Expand" class="commentLink">{{clean_client_list|length}}</a> nodes are clean.<br /></span>
+ <div class="items" id="goodsummary"><ul class="plain">
+ {% for client in clean_client_list|sortname %}
+ {% set_interaction "foo" %}
+ <li><b>Node: </b></tt>
+ <tt><a href="{% block linkprefix1 %}#{% endblock %}{{client.name}}">{{client.name}}</a></tt><span class="mini-date">{{interaction.timestamp}}</span></li>
+ {% endfor %}
+ </ul></div>
+ </div>
+ {% endif %}
+ {% if bad_client_list %}
+ <div class="bad">
+ <span class="nodelisttitle"><a href="javascript:toggleLayer('badsummary');" title="Click to Expand" class="commentLink">{{bad_client_list|length}}</a> nodes are bad.<br /></span>
+ <div class="items" id="badsummary"><ul class="plain">
+ {% for client in bad_client_list|sortname %}
+ {% set_interaction "foo" %}
+ <li><b>Node: </b></tt>
+ <tt><a href="{% block linkprefix2 %}#{% endblock %}{{client.name}}">{{client.name}}</a></tt><span class="mini-date">{{interaction.timestamp}}</span></li>
+ {% endfor %}
+ </ul></div>
+ </div>
+ {% endif %}
+ {% if modified_client_list %}
+ <div class="modified">
+ <span class="nodelisttitle"><a href="javascript:toggleLayer('modifiedsummary');" title="Click to Expand" class="commentLink">{{modified_client_list|length}}</a> nodes were modified in the previous run.<br /></span>
+ <div class="items" id="modifiedsummary"><ul class="plain">
+ {% for client in modified_client_list|sortname %}
+ {% set_interaction "foo" %}
+ <li><b>Node: </b></tt>
+ <tt><a href="{% block linkprefix3 %}#{% endblock %}{{client.name}}">{{client.name}}</a></tt><span class="mini-date">{{interaction.timestamp}}</span></li>
+ {% endfor %}
+ </ul></div>
+ </div>
+ {% endif %}
+ {% if extra_client_list %}
+ <div class="extra">
+ <span class="nodelisttitle"><a href="javascript:toggleLayer('extrasummary');" title="Click to Expand" class="commentLink">{{extra_client_list|length}}</a> nodes have extra configuration. (includes both good and bad nodes)<br /></span>
+ <div class="items" id="extrasummary"><ul class="plain">
+ {% for client in extra_client_list|sortname %}
+ {% set_interaction "foo" %}
+ <li><b>Node: </b></tt>
+ <tt><a href="{% block linkprefix4 %}#{% endblock %}{{client.name}}">{{client.name}}</a></tt><span class="mini-date">{{interaction.timestamp}}</span></li>
+ {% endfor %}
+ </ul></div>
+ </div>
+ {% endif %}
+ {% if stale_up_client_list %}
+ <div class="warning">
+ <span class="nodelisttitle"><a href="javascript:toggleLayer('vstalesummary');" title="Click to Expand" class="commentLink">{{stale_up_client_list|length}}</a> nodes did not run within the last 24 hours but were pingable.<br /></span>
+ <div class="items" id="vstalesummary"><ul class="plain">
+ {% for client in stale_up_client_list|sortname %}
+ {% set_interaction "foo" %}
+ <li><b>Node: </b></tt>
+ <tt><a href="{% block linkprefix5 %}#{% endblock %}{{client.name}}">{{client.name}}</a></tt><span class="mini-date">{{interaction.timestamp}}</span></li>
+ {% endfor %}
+ </ul></div>
+ </div>
+ {% endif %}
+ {% if stale_all_client_list %}
+ <div class="all-warning">
+ <span class="nodelisttitle"><a href="javascript:toggleLayer('stalesummary');" title="Click to Expand" class="commentLink">{{stale_all_client_list|length}}</a> nodes did not run within the last 24 hours. (includes nodes up and down)<br /></span>
+ <div class="items" id="stalesummary"><ul class="plain">
+ {% for client in stale_all_client_list|sortname %}
+ {% set_interaction "foo" %}
+ <li><b>Node: </b></tt>
+ <tt><a href="{% block linkprefix6 %}#{% endblock %}{{client.name}}">{{client.name}}</a></tt><span class="mini-date">{{interaction.timestamp}}</span></li>
+ {% endfor %}
+ </ul></div>
+ </div>
+ {% endif %}
+ {% if down_client_list %}
+ <div class="down">
+ <span class="nodelisttitle"><a href="javascript:toggleLayer('unpingablesummary');" title="Click to Expand" class="commentLink">{{down_client_list|length}}</a> nodes were down.<br /></span>
+ <div class="items" id="unpingablesummary"><ul class="plain">
+ {% for client in down_client_list|sortname %}
+ {% set_interaction "foo" %}
+ <li><b>Node: </b></tt>
+ <tt><a href="#{{client.name}}">{{client.name}}</a></tt><span class="mini-date">{{interaction.timestamp}}</span></li>
+ {% endfor %}
+ </ul></div>
+ </div>
+ {% endif %}
+ </div> \ No newline at end of file
diff --git a/src/lib/Server/Reports/reports/templates/displays/summary.html b/src/lib/Server/Reports/reports/templates/displays/summary.html
new file mode 100644
index 000000000..cf253c25c
--- /dev/null
+++ b/src/lib/Server/Reports/reports/templates/displays/summary.html
@@ -0,0 +1,29 @@
+{% extends "base.html" %}
+{% block extra_header_info %}
+<script type="text/javascript" src="/site_media/CalendarPopup.js"></script>
+<script language="JavaScript">var cal = new CalendarPopup();</script>
+{% endblock%}
+{% block title %}Display Index Listing{% endblock %}
+{% block pagebanner %}
+ <div class="header">
+ <h1>BCFG Clients Summary</h1>
+ <span class="notebox">Report Run @ {% now "F j, Y P"%}</span>
+ </div>
+ <br/>
+{% endblock %}
+
+{% block content %}
+<div>
+<span class="mini-date">
+<b>Enter date or use calendar popup: </b>
+<form name="timestamp-select">
+<input type="text" name="date1" value="{{timestamp_date}}" size=10>@
+<input type="text" name="time" value="{{timestamp_time}}" size=8>
+<a href="" onClick="cal.select(document.forms['timestamp-select'].date1,'anchor1','yyyy-MM-dd'); return false;"
+ name="anchor1" ID="anchor1">Calendar</A>
+<input type="button" name="go" value="Go" onClick="location.href='/displays/summary/'+document.forms['timestamp-select'].date1.value+'@'+document.forms['timestamp-select'].time.value;" />
+ | <input type="button" name="now" value="Now" onClick="location.href='/displays/summary/';"/>
+</form>
+</span><br/><br/><br/></div>
+ {% include "displays/summary-block-direct-links.html" %}
+{% endblock %}
diff --git a/src/lib/Server/Reports/reports/templates/displays/sys_view.html b/src/lib/Server/Reports/reports/templates/displays/sys_view.html
new file mode 100644
index 000000000..1298059bf
--- /dev/null
+++ b/src/lib/Server/Reports/reports/templates/displays/sys_view.html
@@ -0,0 +1,20 @@
+{% extends "base.html" %}
+{% load django_templating_sigh %}
+
+{% block title %}System-View Display{% endblock %}
+{% block pagebanner %}
+ <div class="header">
+ <h1>Grand System View</h1>
+ <span class="notebox">Report Run @ {% now "F j, Y P"%}</span>
+ </div>
+ <br/>
+{% endblock %}
+{% block content %}
+<center><h2>This view is deprecated and will be removed soon.</h2><br/>Please use the "Summary" view and drill down instead.</center>
+
+ {% include "displays/summary-block.html" %}
+ {% for client in client_list %}
+ {% set_interaction "foo" %}
+ {% include "clients/client-nodebox.html" %}
+ {% endfor %}
+{% endblock %}
diff --git a/src/lib/Server/Reports/reports/templates/displays/timing.html b/src/lib/Server/Reports/reports/templates/displays/timing.html
new file mode 100644
index 000000000..e9020b8ef
--- /dev/null
+++ b/src/lib/Server/Reports/reports/templates/displays/timing.html
@@ -0,0 +1,52 @@
+{% extends "base.html" %}
+
+{% block extra_header_info %}
+<script type="text/javascript" src="/site_media/sorttable.js"></script>
+<script type="text/javascript" src="/site_media/CalendarPopup.js"></script>
+<script language="JavaScript">var cal = new CalendarPopup();</script>
+{% endblock%}
+{% block title %}Display Index Listing{% endblock %}
+
+{% block content %}
+ <div class="header">
+ <h1>BCFG Performance Timings</h1>
+ <span class="notebox">Report Run @ {% now "F j, Y P"%}</span>
+ </div>
+ <br/>
+<div>
+<span class="mini-date">
+<b>Enter date or use calendar popup: </b>
+<form name="timestamp-select">
+<input type="text" name="date1" value="{{timestamp_date}}" size=10>@
+<input type="text" name="time" value="{{timestamp_time}}" size=8>
+<a href="" onClick="cal.select(document.forms['timestamp-select'].date1,'anchor1','yyyy-MM-dd'); return false;"
+ name="anchor1" ID="anchor1">Calendar</A>
+<input type="button" name="go" value="Go" onClick="location.href='/displays/timing/'+document.forms['timestamp-select'].date1.value+'@'+document.forms['timestamp-select'].time.value;" />
+ | <input type="button" name="now" value="Now" onClick="location.href='/displays/timing/';"/>
+</form>
+</span><br/><br/><br/></div>
+ <center>
+ <table id="t1" class="sortable">
+ <tr>
+ <th class="sortable">Hostname</th>
+ <th class="sortable">Parse</th>
+ <th class="sortable">Probe</th>
+ <th class="sortable">Inventory</th>
+ <th class="sortable">Install</th>
+ <th class="sortable">Config</th>
+ <th class="sortable">Total</th>
+ </tr>
+ {% for dict_unit in stats_list %}
+ <tr>
+ <td class="sortable"><a href="/clients/{{dict_unit.name}}/">{{dict_unit.name}}</a></td>
+ <td class="sortable">{{dict_unit.parse}}</td>
+ <td class="sortable">{{dict_unit.probe}}</td>
+ <td class="sortable">{{dict_unit.inventory}}</td>
+ <td class="sortable">{{dict_unit.install}}</td>
+ <td class="sortable">{{dict_unit.config}}</td>
+ <td class="sortable">{{dict_unit.total}}</td>
+ </tr>
+ {% endfor %}
+ </table>
+ </center>
+{% endblock %} \ No newline at end of file
diff --git a/src/lib/Server/Reports/reports/templates/index.html b/src/lib/Server/Reports/reports/templates/index.html
new file mode 100644
index 000000000..002a3f770
--- /dev/null
+++ b/src/lib/Server/Reports/reports/templates/index.html
@@ -0,0 +1,15 @@
+{% extends "base.html" %}
+
+{% block pagebanner %}
+ <div class="header">
+ <h1>BCFG Reports</h1>
+ {% comment %} <span class="notebox">Report Run @ {% now "F j, Y P"%}</span>{% endcomment %}
+ </div>
+ <br/>
+{% endblock %}
+{% block content %}
+<h1>Welcome to the Bcfg2 Reporting System</h1>
+<p>
+Please use the links at the left to navigate.
+</p>
+{% endblock %}
diff --git a/src/lib/Server/Reports/reports/templatetags/__init__.py b/src/lib/Server/Reports/reports/templatetags/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/lib/Server/Reports/reports/templatetags/__init__.py
diff --git a/src/lib/Server/Reports/reports/templatetags/django_templating_sigh.py b/src/lib/Server/Reports/reports/templatetags/django_templating_sigh.py
new file mode 100644
index 000000000..85f4d61a2
--- /dev/null
+++ b/src/lib/Server/Reports/reports/templatetags/django_templating_sigh.py
@@ -0,0 +1,40 @@
+from django import template
+#from brpt.reports.models import Client, Interaction, Bad, Modified, Extra
+
+register = template.Library()
+
+def set_interaction(parser, token):
+ try:
+ # Splitting by None == splitting by spaces.
+ tag_name, format_string = token.contents.split(None, 1)
+ except ValueError:
+ raise template.TemplateSyntaxError, "%r tag requires an argument" % token.contents[0]
+ if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")):
+ raise template.TemplateSyntaxError, "%r tag's argument should be in quotes" % tag_name
+ return SetInteraction(format_string[1:-1])
+
+def sortwell(value):
+ "sorts a list(or evaluates queryset to list) of bad, extra, or modified items in the best way for presentation"
+ configItems = list(value)
+ configItems.sort(lambda x,y: cmp(x.name, y.name))
+ configItems.sort(lambda x,y: cmp(x.kind, y.kind))
+ return configItems
+def sortname(value):
+ "sorts a list( or evaluates queryset) by name"
+ configItems = list(value)
+ configItems.sort(lambda x,y: cmp(x.name, y.name))
+ return configItems
+
+class SetInteraction(template.Node):
+ def __init__(self, times):
+ self.times = times#do soemthing to select different interaction with host?
+ def render(self, context):
+ try:
+ context['interaction'] = context['client_interaction_dict'][context['client'].id]
+ except:#I don't fully know what the implications of this are.
+ pass
+ return ''
+
+register.tag('set_interaction', set_interaction)
+register.filter('sortwell', sortwell)
+register.filter('sortname', sortname)
diff --git a/src/lib/Server/Reports/reports/views.py b/src/lib/Server/Reports/reports/views.py
new file mode 100644
index 000000000..44c858a82
--- /dev/null
+++ b/src/lib/Server/Reports/reports/views.py
@@ -0,0 +1,255 @@
+# Create your views here.
+#from django.shortcuts import get_object_or_404, render_to_response
+from django.template import Context, loader
+from django.http import HttpResponseRedirect, HttpResponse
+from django.shortcuts import render_to_response, get_object_or_404
+from brpt.reports.models import Client, Interaction, Bad, Modified, Extra, Performance, Reason
+from datetime import datetime, timedelta
+from time import strptime
+from django.db import connection
+from django.db.backends import util
+from django.contrib.auth.decorators import login_required
+
+def index(request):
+ return render_to_response('index.html')
+
+def config_item_modified(request, eyedee =None, timestamp = 'now'):
+ #if eyedee = None, dump with a 404
+ timestamp = timestamp.replace("@"," ")
+ mod_or_bad = "modified"
+
+ item = Modified.objects.get(id=eyedee)
+ #if everything is blank except current_exists, do something special
+ cursor = connection.cursor()
+ if timestamp == 'now':
+ cursor.execute("select client_id from reports_interaction, reports_modified_interactions, reports_client "+
+ "WHERE reports_client.current_interaction_id = reports_modified_interactions.interaction_id "+
+ "AND reports_modified_interactions.interaction_id = reports_interaction.id "+
+ "AND reports_modified_interactions.modified_id = %s", [eyedee])
+ associated_client_list = Client.objects.filter(id__in=[x[0] for x in cursor.fetchall()])
+ else:
+ interact_queryset = Interaction.objects.interaction_per_client(timestamp)
+ interactionlist = []
+ [interactionlist.append(x.id) for x in interact_queryset]
+ if not interactionlist == []:
+ cursor.execute("select client_id from reports_interaction, reports_modified_interactions, reports_client "+
+ "WHERE reports_modified_interactions.interaction_id IN %s "+
+ "AND reports_modified_interactions.interaction_id = reports_interaction.id "+
+ "AND reports_modified_interactions.modified_id = %s", [interactionlist, eyedee])
+ associated_client_list = Client.objects.filter(id__in=[x[0] for x in cursor.fetchall()])
+ else:
+ associated_client_list = []
+
+ if timestamp == 'now':
+ timestamp = datetime.now().isoformat('@')
+
+ return render_to_response('config_items/index.html', {'item':item,
+ 'mod_or_bad':mod_or_bad,
+ 'associated_client_list':associated_client_list,
+ 'timestamp' : timestamp,
+ 'timestamp_date' : timestamp[:10],
+ 'timestamp_time' : timestamp[11:19]})
+
+
+def config_item_bad(request, eyedee = None, timestamp = 'now'):
+ timestamp = timestamp.replace("@"," ")
+ mod_or_bad = "bad"
+ item = Bad.objects.get(id=eyedee)
+ cursor = connection.cursor()
+ if timestamp == 'now':
+ cursor.execute("select client_id from reports_interaction, reports_bad_interactions, reports_client "+
+ "WHERE reports_client.current_interaction_id = reports_bad_interactions.interaction_id "+
+ "AND reports_bad_interactions.interaction_id = reports_interaction.id "+
+ "AND reports_bad_interactions.bad_id = %s", [eyedee])
+ associated_client_list = Client.objects.filter(id__in=[x[0] for x in cursor.fetchall()])
+ else:
+ interact_queryset = Interaction.objects.interaction_per_client(timestamp)
+ interactionlist = []
+ [interactionlist.append(x.id) for x in interact_queryset]
+ if not interactionlist == []:
+ cursor.execute("SELECT DISTINCT client_id from reports_interaction, reports_bad_interactions, reports_client "+
+ "WHERE reports_bad_interactions.interaction_id IN %s "+
+ "AND reports_bad_interactions.interaction_id = reports_interaction.id "+
+ "AND reports_bad_interactions.bad_id = %s", [interactionlist, eyedee])
+ associated_client_list = Client.objects.filter(id__in=[x[0] for x in cursor.fetchall()])
+ else:
+ associated_client_list = None
+
+ if timestamp == 'now':
+ timestamp = datetime.now().isoformat('@')
+
+ return render_to_response('config_items/index.html', {'item':item,
+ 'mod_or_bad':mod_or_bad,
+ 'associated_client_list':associated_client_list,
+ 'timestamp' : timestamp,
+ 'timestamp_date' : timestamp[:10],
+ 'timestamp_time' : timestamp[11:19]})
+
+
+
+def client_index(request):
+ client_list = Client.objects.all().order_by('name')
+ client_list_a = client_list[:len(client_list)/2]
+ client_list_b = client_list[len(client_list)/2:]
+ return render_to_response('clients/index.html', {'client_list_a': client_list_a,
+ 'client_list_b': client_list_b})
+
+def client_detail(request, hostname = None, pk = None):
+ #SETUP error pages for when you specify a client or interaction that doesn't exist
+ client = get_object_or_404(Client, name=hostname)
+ if(pk == None):
+ interaction = client.current_interaction
+ else:
+ interaction = client.interactions.get(pk=pk)#can this be a get object or 404?
+ return render_to_response('clients/detail.html', {'client': client, 'interaction': interaction})
+
+def display_sys_view(request, timestamp = 'now'):
+ client_lists = prepare_client_lists(request, timestamp)
+ return render_to_response('displays/sys_view.html', client_lists)
+
+def display_summary(request, timestamp = 'now'):
+
+ client_lists = prepare_client_lists(request, timestamp)
+ #this returns timestamp and the timestamp parts too
+ return render_to_response('displays/summary.html', client_lists)
+
+def display_timing(request, timestamp = 'now'):
+ #We're going to send a list of dictionaries. Each dictionary will be a row in the table
+ #+------+-------+----------------+-----------+---------+----------------+-------+
+ #| name | parse | probe download | inventory | install | cfg dl & parse | total |
+ #+------+-------+----------------+-----------+---------+----------------+-------+
+ client_list = Client.objects.all().order_by('name')
+ stats_list = []
+
+ if not timestamp == 'now':
+ results = Performance.objects.performance_per_client(timestamp.replace("@"," "))
+ else:
+ results = Performance.objects.performance_per_client()
+ timestamp = datetime.now().isoformat('@')
+
+ for client in client_list:#Go explicitly to an interaction ID! (new item in dictionary)
+ try:
+ d = results[client.name]
+ except KeyError:
+ d = {}
+
+ dict_unit = {}
+ try:
+ dict_unit["name"] = client.name #node name
+ except:
+ dict_unit["name"] = "n/a"
+ try:
+ dict_unit["parse"] = round(d["config_parse"] - d["config_download"], 4) #parse
+ except:
+ dict_unit["parse"] = "n/a"
+ try:
+ dict_unit["probe"] = round(d["probe_upload"] - d["start"], 4) #probe
+ except:
+ dict_unit["probe"] = "n/a"
+ try:
+ dict_unit["inventory"] = round(d["inventory"] - d["initialization"], 4) #inventory
+ except:
+ dict_unit["inventory"] = "n/a"
+ try:
+ dict_unit["install"] = round(d["install"] - d["inventory"], 4) #install
+ except:
+ dict_unit["install"] = "n/a"
+ try:
+ dict_unit["config"] = round(d["config_parse"] - d["probe_upload"], 4)#config download & parse
+ except:
+ dict_unit["config"] = "n/a"
+ try:
+ dict_unit["total"] = round(d["finished"] - d["start"], 4) #total
+ except:
+ dict_unit["total"] = "n/a"
+
+ stats_list.append(dict_unit)
+
+ return render_to_response('displays/timing.html', {'client_list': client_list,
+ 'stats_list': stats_list,
+ 'timestamp' : timestamp,
+ 'timestamp_date' : timestamp[:10],
+ 'timestamp_time' : timestamp[11:19]})
+
+def display_index(request):
+ return render_to_response('displays/index.html')
+
+def prepare_client_lists(request, timestamp = 'now'):
+ timestamp = timestamp.replace("@"," ")
+ #client_list = Client.objects.all().order_by('name')#change this to order by interaction's state
+ client_interaction_dict = {}
+ clean_client_list = []
+ bad_client_list = []
+ extra_client_list = []
+ modified_client_list = []
+ stale_up_client_list = []
+ #stale_all_client_list = []
+ down_client_list = []
+
+ cursor = connection.cursor()
+
+ interact_queryset = Interaction.objects.interaction_per_client(timestamp)
+ # or you can specify a time like this: '2007-01-01 00:00:00'
+ [client_interaction_dict.__setitem__(x.client_id,x) for x in interact_queryset]
+ client_list = Client.objects.filter(id__in=client_interaction_dict.keys()).order_by('name')
+
+ [clean_client_list.append(x) for x in Client.objects.filter(id__in=[y.client_id for y in interact_queryset.filter(state='clean')])]
+ [bad_client_list.append(x) for x in Client.objects.filter(id__in=[y.client_id for y in interact_queryset.filter(state='dirty')])]
+
+ client_ping_dict = {}
+ [client_ping_dict.__setitem__(x,'Y') for x in client_interaction_dict.keys()]#unless we know otherwise...
+
+ try:
+ cursor.execute("select reports_ping.status, x.client_id from (select client_id, MAX(endtime) "+
+ "as timer from reports_ping GROUP BY client_id) x, reports_ping where "+
+ "reports_ping.client_id = x.client_id AND reports_ping.endtime = x.timer")
+ [client_ping_dict.__setitem__(x[1],x[0]) for x in cursor.fetchall()]
+ except:
+ pass #This is to fix problems when you have only zero records returned
+
+ client_down_ids = [y for y in client_ping_dict.keys() if client_ping_dict[y]=='N']
+ if not client_down_ids == []:
+ [down_client_list.append(x) for x in Client.objects.filter(id__in=client_down_ids)]
+
+ if (timestamp == 'now' or timestamp == None):
+ cursor.execute("select client_id, MAX(timestamp) as timestamp from reports_interaction GROUP BY client_id")
+ results = cursor.fetchall()
+ for x in results:
+ if type(x[1]) == type(""):
+ x[1] = util.typecast_timestamp(x[1])
+ stale_all_client_list = Client.objects.filter(id__in=[x[0] for x in results if datetime.now() - x[1] > timedelta(days=1)])
+ else:
+ cursor.execute("select client_id, timestamp, MAX(timestamp) as timestamp from reports_interaction "+
+ "WHERE timestamp < %s GROUP BY client_id", [timestamp])
+ t = strptime(timestamp,"%Y-%m-%d %H:%M:%S")
+ datetimestamp = datetime(t[0], t[1], t[2], t[3], t[4], t[5])
+ results = cursor.fetchall()
+ for x in results:
+ if type(x[1]) == type(""):
+ x[1] = util.typecast_timestamp(x[1])
+ stale_all_client_list = Client.objects.filter(id__in=[x[0] for x in results if datetimestamp - x[1] > timedelta(days=1)])
+
+ [stale_up_client_list.append(x) for x in stale_all_client_list if not client_ping_dict[x.id]=='N']
+
+
+ cursor.execute("SELECT reports_client.id FROM reports_client, reports_interaction, reports_modified_interactions WHERE reports_client.id=reports_interaction.client_id AND reports_interaction.id = reports_modified_interactions.interaction_id GROUP BY reports_client.id")
+ modified_client_list = Client.objects.filter(id__in=[x[0] for x in cursor.fetchall()])
+
+ cursor.execute("SELECT reports_client.id FROM reports_client, reports_interaction, reports_extra_interactions WHERE reports_client.id=reports_interaction.client_id AND reports_interaction.id = reports_extra_interactions.interaction_id GROUP BY reports_client.id")
+ extra_client_list = Client.objects.filter(id__in=[x[0] for x in cursor.fetchall()])
+
+ if timestamp == 'now':
+ timestamp = datetime.now().isoformat('@')
+
+ return {'client_list': client_list,
+ 'client_interaction_dict':client_interaction_dict,
+ 'clean_client_list': clean_client_list,
+ 'bad_client_list': bad_client_list,
+ 'extra_client_list': extra_client_list,
+ 'modified_client_list': modified_client_list,
+ 'stale_up_client_list': stale_up_client_list,
+ 'stale_all_client_list': stale_all_client_list,
+ 'down_client_list': down_client_list,
+ 'timestamp' : timestamp,
+ 'timestamp_date' : timestamp[:10],
+ 'timestamp_time' : timestamp[11:19]}