From 28e240eb7def09d695bff401226193faffbbd59a Mon Sep 17 00:00:00 2001
From: Stephen Soltesz <soltesz@cs.princeton.edu>
Date: Thu, 25 Jun 2009 23:01:59 +0000
Subject: [PATCH] added references to google gadgets added sitesummary and
 summary controls for gadgets clarified sitehistory, and other history views
 simplified controllers.py in many places, trying to make node() faster.

---
 web/MonitorWeb/monitorweb/controllers.py      | 74 +++++++++++++++++--
 .../monitorweb/static/css/style.css           |  5 +-
 .../monitorweb/static/xml/gadget.xml          |  4 +-
 .../monitorweb/static/xml/sitemonitor.xml     |  4 +-
 web/MonitorWeb/monitorweb/templates/links.py  |  2 +
 .../monitorweb/templates/nodehistory.kid      | 29 +-------
 .../monitorweb/templates/pcuhistory.kid       | 31 ++------
 .../monitorweb/templates/sitehistory.kid      |  9 ++-
 .../monitorweb/templates/sitesummary.kid      | 41 ++++++++++
 .../monitorweb/templates/summary.kid          | 38 ++++++++++
 .../monitorweb/templates/welcome.kid          | 11 ++-
 11 files changed, 179 insertions(+), 69 deletions(-)
 create mode 100644 web/MonitorWeb/monitorweb/templates/sitesummary.kid
 create mode 100644 web/MonitorWeb/monitorweb/templates/summary.kid

diff --git a/web/MonitorWeb/monitorweb/controllers.py b/web/MonitorWeb/monitorweb/controllers.py
index a1746c8..60bdbcc 100644
--- a/web/MonitorWeb/monitorweb/controllers.py
+++ b/web/MonitorWeb/monitorweb/controllers.py
@@ -108,12 +108,16 @@ def prep_pcu_for_display(pcu):
 class NodeWidget(widgets.Widget):
 	pass
 
-def prep_node_for_display(node):
+def prep_node_for_display(node, pcuhash=None):
 	agg = aggregate()
 	agg.node = node
 
 	if node.plc_pcuid:
-		pcu = FindbadPCURecord.get_latest_by(plc_pcuid=node.plc_pcuid)
+		if pcuhash:
+			pcu = pcuhash[node.plc_pcuid]
+		else:
+			pcu = FindbadPCURecord.get_latest_by(plc_pcuid=node.plc_pcuid)
+
 		if pcu:
 			agg.pcu_status = pcu.reboot_trial_status
 			agg.pcu_short_status = format_pcu_shortstatus(pcu)
@@ -167,6 +171,31 @@ class Root(controllers.RootController, MonitorXmlrpcServer):
 		flash("Welcome To MyOps!")
 		return dict(now=time.ctime())
 
+	@expose(template="monitorweb.templates.nodelist")
+	def node2(self, filter='boot'):
+
+		fbquery = FindbadNodeRecord.get_all_latest()
+		fbpcus = FindbadPCURecord.get_all_latest()
+		def fbtohash(fbpculist):
+			h = {}
+			for p in fbpculist:
+				h[p.plc_pcuid] = p
+
+		pcuhash = fbtohash(fbpcus)
+
+		query = []
+		for node in fbquery:
+			# NOTE: reformat some fields.
+			agg = prep_node_for_display(node, pcuhash)
+
+			if not agg.history:
+				continue
+
+			query.append(agg)
+				
+		widget = NodeWidget(template='monitorweb.templates.node_template')
+		return dict(now=time.ctime(), query=query, nodewidget=widget)
+
 	@expose(template="monitorweb.templates.nodelist")
 	def node(self, filter='boot'):
 		print "NODE------------------"
@@ -181,9 +210,6 @@ class Root(controllers.RootController, MonitorXmlrpcServer):
 			# NOTE: reformat some fields.
 			agg = prep_node_for_display(node)
 
-			#node.history.status
-			#print node.hostname
-
 			if not agg.history:
 				continue
 
@@ -197,9 +223,6 @@ class Root(controllers.RootController, MonitorXmlrpcServer):
 			elif agg.history.status in ['debug', 'monitordebug']:
 				filtercount['debug'] += 1
 			else:
-				# TODO: need a better fix. filtercount
-				# doesn't maps to GetBootStates() on
-				# 4.3 so this one fails quite often.
 				if filtercount.has_key(agg.history.status):
 					filtercount[agg.history.status] += 1
 				
@@ -462,6 +485,41 @@ class Root(controllers.RootController, MonitorXmlrpcServer):
 				query.append(site)
 				
 		return dict(query=query, fc=filtercount)
+	@expose(template="monitorweb.templates.sitesummary")
+	def sitesummary(self, loginbase="princeton"):
+		nodequery = []
+		for node in FindbadNodeRecord.query.filter_by(loginbase=loginbase):
+			agg = prep_node_for_display(node)
+			nodequery += [agg]
+		
+		return dict(nodequery=nodequery, loginbase=loginbase)
+
+	@expose(template="monitorweb.templates.summary")
+	def summary(self, since=7):
+		sumdata = {}
+		sumdata['nodes'] = {}
+		sumdata['sites'] = {}
+		sumdata['pcus'] = {}
+
+		def summarize(query, type):
+			for o in query:
+				if o.status not in sumdata[type]:
+					sumdata[type][o.status] = 0
+				sumdata[type][o.status] += 1
+
+		fbquery = HistorySiteRecord.query.all()
+		summarize(fbquery, 'sites')
+		fbquery = HistoryPCURecord.query.all()
+		summarize(fbquery, 'pcus')
+		fbquery = HistoryNodeRecord.query.all()
+		summarize(fbquery, 'nodes')
+
+		if 'monitordebug' in sumdata['nodes']:
+			d = sumdata['nodes']['monitordebug']
+			del sumdata['nodes']['monitordebug']
+			sumdata['nodes']['failboot'] = d
+		
+		return dict(sumdata=sumdata, setorder=['good', 'offline', 'down', 'online']) 
 
 	@expose(template="monitorweb.templates.actionsummary")
 	def actionsummary(self, since=7):
diff --git a/web/MonitorWeb/monitorweb/static/css/style.css b/web/MonitorWeb/monitorweb/static/css/style.css
index d3a365c..ac85b33 100644
--- a/web/MonitorWeb/monitorweb/static/css/style.css
+++ b/web/MonitorWeb/monitorweb/static/css/style.css
@@ -108,6 +108,9 @@ a.right { float: right; }
 #site-offline { background-color: red; }
 #site-down { background-color: indianred; }
 
+#site-True { background-color : darkseagreen; }
+#site-False { background-color: indianred; }
+
 #node-online { background-color : lightgreen; }
 #node-good { background-color : darkseagreen; }
 #node-offline { background-color: red; }
@@ -118,7 +121,7 @@ a.right { float: right; }
 #pcu-offline { background-color: red; }
 #pcu-down { background-color: indianred; }
 
-/*#site-0 { background-color : white; }*/
+#site-0 { background-color : darkseagreen ; }
 #site-1 { background-color: gold; }
 #site-2 { background-color: indianred; }
 
diff --git a/web/MonitorWeb/monitorweb/static/xml/gadget.xml b/web/MonitorWeb/monitorweb/static/xml/gadget.xml
index 8a3c79a..bae4356 100644
--- a/web/MonitorWeb/monitorweb/static/xml/gadget.xml
+++ b/web/MonitorWeb/monitorweb/static/xml/gadget.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Module>
-<ModulePrefs title="Monitor Node Count" title_url="http://www.planet-lab.org">
+<ModulePrefs title="MyOps Summary" title_url="http://www.planet-lab.org">
 <Require feature="dynamic-height"/>
 </ModulePrefs>
 <Content type="html"><![CDATA[
@@ -10,7 +10,7 @@ var displaycontent = function (responseText) {
 	_gel('content_div').innerHTML = responseText; 
 	_IG_AdjustIFrameHeight();
 };
-_IG_FetchContent('http://monitor.planet-lab.org/monitor/actionsummary', displaycontent, { refreshInterval: 300 }); 
+_IG_FetchContent('http://monitor.planet-lab.org/monitor/summary', displaycontent, { refreshInterval: 300 }); 
 </script>
 ]]></Content>
 </Module>
diff --git a/web/MonitorWeb/monitorweb/static/xml/sitemonitor.xml b/web/MonitorWeb/monitorweb/static/xml/sitemonitor.xml
index 0bb0b02..2b2c4ad 100644
--- a/web/MonitorWeb/monitorweb/static/xml/sitemonitor.xml
+++ b/web/MonitorWeb/monitorweb/static/xml/sitemonitor.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Module>
-	<ModulePrefs title="PlanetLab Site Status" title_url="http://www.planet-lab.org">
+	<ModulePrefs title="MyOps Site Status" title_url="http://www.planet-lab.org">
 		<Require feature="dynamic-height"/>
 	</ModulePrefs>
 	<UserPref name="loginBase" display_name="Site Login Base" 
@@ -13,7 +13,7 @@ var displaycontent = function (responseText) {
 	_gel('content_div').innerHTML = responseText; 
 	_IG_AdjustIFrameHeight();
 };
-var url = 'http://monitor.planet-lab.org/monitor/actionlist?loginbase=' + prefs.getString("loginBase");
+var url = 'http://monitor.planet-lab.org/monitor/sitesummary?loginbase=' + prefs.getString("loginBase");
 _IG_FetchContent(url, displaycontent, { refreshInterval: 1200 }); 
 </script>
 ]]></Content>
diff --git a/web/MonitorWeb/monitorweb/templates/links.py b/web/MonitorWeb/monitorweb/templates/links.py
index 95f192e..1a951bd 100644
--- a/web/MonitorWeb/monitorweb/templates/links.py
+++ b/web/MonitorWeb/monitorweb/templates/links.py
@@ -2,6 +2,8 @@ from monitor import config
 import turbogears as tg
 import urllib
 
+def plc_myops_uri():
+	return "http://" + config.MONITOR_HOSTNAME 
 def plc_mail_uri(ticketid):
 	return config.RT_WEB_SERVER + "/Ticket/Display.html?id=" + str(ticketid)
 def plc_node_uri(hostname):
diff --git a/web/MonitorWeb/monitorweb/templates/nodehistory.kid b/web/MonitorWeb/monitorweb/templates/nodehistory.kid
index de60dd9..e63d957 100644
--- a/web/MonitorWeb/monitorweb/templates/nodehistory.kid
+++ b/web/MonitorWeb/monitorweb/templates/nodehistory.kid
@@ -18,37 +18,16 @@ from links import *
 		<table id="sortable_table" class="datagrid" border="1" width="100%">
 			<thead>
 				<tr>
-					<th mochi:format="int"></th>
-					<!--th>Site</th>
-					<th>pcu</th-->
-					<th>date</th>
+					<th>Last Check</th>
+					<th>Last Change</th>
 					<th>hostname</th>
-					<th>last_contact</th>
+					<th>Status</th>
 				</tr>
 			</thead>
 			<tbody>
 				<tr py:for="i,node in enumerate(query)" class="${i%2 and 'odd' or 'even'}" >
-					<td></td>
-					<!--td id="site-${node.site.status}">
-						<a href="${link('pcuview', loginbase=node.loginbase)}">${node.loginbase}</a>
-					</td>
-					<td width="20%" nowrap='true' align='center' id="status-${node.pcu_short_status}">
-						<div id="links">
-							<a class="info" py:if="'error' in node.pcu_short_status" 
-								href="${link('pcuview', pcuid=node.plc_pcuid)}">
-							Error<span><pre>${node.pcu.reboot_trial_status}</pre></span></a>
-							<a py:if="'error' not in node.pcu_short_status and 'none' not in node.pcu_short_status" 
-								href="${link('pcuview', pcuid=node.plc_pcuid)}"
-								py:content="node.pcu_short_status">Reboot Status</a>
-							<span py:if="'none' in node.pcu_short_status" 
-								py:content="node.pcu_short_status">Reboot Status</span>
-						</div>
-					</td-->
-					<!--td id="node-${node.observed_status}" nowrap="true">
-						<a target="_top" href="${link('pcuview', hostname=node.hostname)}" py:content="node.hostname">your.host.org</a></td-->
-					<!--td nowrap="true" py:content="node.kernel"></td-->
-					<!--td py:content="node.date_checked"></td-->
 					<td py:content="node.last_checked"></td>
+					<td py:content="diff_time(mktime(node.last_changed.timetuple()))"></td>
 					<td nowrap="true">
 						<a target="_top" href="${link('pcuview', hostname=node.hostname)}" py:content="node.hostname">your.host.org</a></td>
 					<td id="node-${node.status}" py:content="node.status"></td>
diff --git a/web/MonitorWeb/monitorweb/templates/pcuhistory.kid b/web/MonitorWeb/monitorweb/templates/pcuhistory.kid
index 79fd07b..d809609 100644
--- a/web/MonitorWeb/monitorweb/templates/pcuhistory.kid
+++ b/web/MonitorWeb/monitorweb/templates/pcuhistory.kid
@@ -10,7 +10,7 @@ from links import *
 	  xmlns:mochi="http://www.mochi.org">
 
   <div py:match="item.tag == 'content'">
-  	<h3>Node History : ${pcu_id}</h3>
+  	<h3>PCU History for pcu_id : <a href="${plc_pcu_uri_id(pcu_id)}">${pcu_id}</a></h3>
   	<table width="100%">
 		<tbody>
 		<tr>
@@ -18,37 +18,16 @@ from links import *
 		<table id="sortable_table" class="datagrid" border="1" width="100%">
 			<thead>
 				<tr>
-					<th mochi:format="int"></th>
-					<!--th>Site</th>
-					<th>pcu</th-->
-					<th>date</th>
+					<th>Last Check</th>
+					<th>Last Change</th>
 					<th>pcu_id</th>
-					<th>last_contact</th>
+					<th>Status</th>
 				</tr>
 			</thead>
 			<tbody>
 				<tr py:for="i,pcu in enumerate(query)" class="${i%2 and 'odd' or 'even'}" >
-					<td></td>
-					<!--td id="site-${node.site.status}">
-						<a href="${link('pcuview', loginbase=node.loginbase)}">${node.loginbase}</a>
-					</td>
-					<td width="20%" nowrap='true' align='center' id="status-${node.pcu_short_status}">
-						<div id="links">
-							<a class="info" py:if="'error' in node.pcu_short_status" 
-								href="${link('pcuview', pcuid=node.plc_pcuid)}">
-							Error<span><pre>${node.pcu.reboot_trial_status}</pre></span></a>
-							<a py:if="'error' not in node.pcu_short_status and 'none' not in node.pcu_short_status" 
-								href="${link('pcuview', pcuid=node.plc_pcuid)}"
-								py:content="node.pcu_short_status">Reboot Status</a>
-							<span py:if="'none' in node.pcu_short_status" 
-								py:content="node.pcu_short_status">Reboot Status</span>
-						</div>
-					</td-->
-					<!--td id="node-${node.observed_status}" nowrap="true">
-						<a target="_top" href="${link('pcuview', hostname=node.hostname)}" py:content="node.hostname">your.host.org</a></td-->
-					<!--td nowrap="true" py:content="node.kernel"></td-->
-					<!--td py:content="node.date_checked"></td-->
 					<td py:content="pcu.last_checked"></td>
+					<td py:content="diff_time(mktime(pcu.last_changed.timetuple()))"></td>
 					<td nowrap="true">
 						<a target="_top" href="${link('pcuview', pcuid=pcu.plc_pcuid)}" py:content="pcu.plc_pcuid">your.host.org</a></td>
 					<td id="pcu-${pcu.status}" py:content="pcu.status"></td>
diff --git a/web/MonitorWeb/monitorweb/templates/sitehistory.kid b/web/MonitorWeb/monitorweb/templates/sitehistory.kid
index 8dfb823..6040d83 100644
--- a/web/MonitorWeb/monitorweb/templates/sitehistory.kid
+++ b/web/MonitorWeb/monitorweb/templates/sitehistory.kid
@@ -20,9 +20,10 @@ from links import *
 				<tr>
 					<th mochi:format="int"></th>
 					<th>Site name</th>
+					<th mochi:format="int">Slices/Max</th>
 					<th>Enabled</th>
 					<th>Penalty</th>
-					<th mochi:format="int">Slices/Max</th>
+					<th>Last Change</th>
 					<th mochi:format="int">Nodes/Total</th>
 					<th>Date Checked</th>
 				</tr>
@@ -37,11 +38,11 @@ from links import *
 							<img style='display: inline' border='0' src="static/images/extlink.gif" align='right'/></a>
 						</div>
 					</td>
-					<td py:content="site.enabled"></td>
-					<td id="site-${site.penalty_level}">${site.penalty_level}</td>
 					<td>${site.slices_used}/${site.slices_total}</td>
-					<td>${site.nodes_up} / ${site.nodes_total}</td>
+					<td id="site-${site.enabled}" py:content="site.enabled"></td>
+					<td id="site-${site.penalty_level}">${site.penalty_level}</td>
 					<td id="site-${site.status}" py:content="diff_time(mktime(site.last_changed.timetuple()))"></td>
+					<td id="site-${site.nodes_up >= 2}">${site.nodes_up} / ${site.nodes_total}</td>
 					<td py:content="site.timestamp"></td>
 				</tr>
 			</tbody>
diff --git a/web/MonitorWeb/monitorweb/templates/sitesummary.kid b/web/MonitorWeb/monitorweb/templates/sitesummary.kid
new file mode 100644
index 0000000..37e0541
--- /dev/null
+++ b/web/MonitorWeb/monitorweb/templates/sitesummary.kid
@@ -0,0 +1,41 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<?python
+layout_params['page_title'] = "MyOps Detail View"
+from monitor.util import diff_time
+from monitor import config
+from time import mktime
+from pcucontrol.reboot import pcu_name, model_to_object
+from links import *
+?>
+<html xmlns:py="http://purl.org/kid/ns#"
+	  xmlns:mochi="http://www.mochi.org">
+  <head>
+    <link href="http://monitor.planet-lab.org/monitor/static/css/style.css" type="text/css" rel="stylesheet" />
+  </head>
+
+	<h3>Nodes for site ${loginbase}</h3> 
+		<p>Working on the color...</p>
+		<p py:if="len(nodequery) == 0">
+			There are no registered nodes for this site.
+		</p>
+		<table py:if="len(nodequery) > 0" id="sortable_table" class="datagrid" border="1" width="100%">
+			<thead>
+				<tr>
+					<th>History</th>
+					<th>Hostname</th>
+					<th>Status</th>
+				</tr>
+			</thead>
+			<tbody>
+				<tr py:for="i,agg in enumerate(nodequery)" class="${i%2 and 'odd' or 'even'}" >
+					<td><a target="_blank" href="nodehistory?hostname=${agg.node.hostname}">history</a></td>
+					<td id="node-${agg.node.observed_status}" nowrap="true" >
+						<a class="ext-link" target="_blank" href="${plc_node_uri_id(agg.node.plc_node_stats['node_id'])}">
+							<span class="icon">${agg.node.hostname}</span></a>
+					</td>
+					<td py:content="agg.node.observed_status" nowrap="true" ></td>
+				</tr>
+			</tbody>
+		</table>
+
+</html>
diff --git a/web/MonitorWeb/monitorweb/templates/summary.kid b/web/MonitorWeb/monitorweb/templates/summary.kid
new file mode 100644
index 0000000..27b888c
--- /dev/null
+++ b/web/MonitorWeb/monitorweb/templates/summary.kid
@@ -0,0 +1,38 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<?python
+layout_params['page_title'] = "MyOps Summary"
+from monitor.util import diff_time
+from monitor import config
+from time import mktime
+from links import *
+?>
+<html 
+      xmlns:py="http://purl.org/kid/ns#"
+	  xmlns:mochi="http://www.mochi.org">
+
+  <?python orig=True ?>
+  	<table>
+		<tbody>
+  		<span py:for="primarykey in ['sites', 'nodes', 'pcus']">
+			<tr>
+    			<td width="50" rowspan="2">${primarykey.capitalize()}</td>
+				<span py:for="i,key in enumerate(setorder + [s for s in set(sumdata[primarykey].keys())-set(setorder)]) ">
+					<th valign="top" py:if="orig and i&lt;4" py:content="key.capitalize()"></th>
+					<th valign="top" py:if="orig and i&gt;3" py:content="key.capitalize()"></th>
+					<th valign="top" py:if="not orig and i&gt;3" py:content="key.capitalize()"></th>
+					<th valign="top" py:if="not orig and i&lt;4" py:content=""></th>
+				</span>
+			</tr>
+			<?python orig=False ?>
+			<tr>
+				<span py:for="key in setorder + [s for s in set(sumdata[primarykey].keys())-set(setorder)]">
+					<td bgcolor="lightgrey" valign="top" align="center" py:content="sumdata[primarykey][key]"></td>
+				</span>
+			</tr>
+  		</span>
+		</tbody>
+	</table>
+<div py:match="item.tag == 'content'">
+</div>
+
+</html>
diff --git a/web/MonitorWeb/monitorweb/templates/welcome.kid b/web/MonitorWeb/monitorweb/templates/welcome.kid
index 43fdc21..af7b007 100644
--- a/web/MonitorWeb/monitorweb/templates/welcome.kid
+++ b/web/MonitorWeb/monitorweb/templates/welcome.kid
@@ -1,4 +1,7 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<?python
+from links import *
+?>
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#"
     py:extends="'master.kid'">
 <head>
@@ -32,7 +35,13 @@
         <p> All nodes: <a href="node">Nodes</a> <br/> </p>
       </li>
     </ol>
-    <!--div class="notice"> If you create something cool, please <a href="http://groups.google.com/group/turbogears">let people know</a>, and consider contributing something back to the <a href="http://groups.google.com/group/turbogears">community</a>.</div-->
+	<p>If you'd like to track things a little more informally, you can install
+	these Google Gadgets for summaries of the entire system or a specific
+	site.</p>
+    <ul class="links">
+      <li><a href="http://fusion.google.com/add?source=atgs&amp;moduleurl=${plc_myops_uri()}/monitor/gadget.xml">MyOps Summary</a></li>
+      <li><a href="http://fusion.google.com/add?source=atgs&amp;moduleurl=${plc_myops_uri()}/monitor/sitemonitor.xml">Site Summary</a></li>
+    </ul>
   </div>
   <!-- End of getting_started -->
 </body>
-- 
2.47.0