added references to google gadgets
authorStephen Soltesz <soltesz@cs.princeton.edu>
Thu, 25 Jun 2009 23:01:59 +0000 (23:01 +0000)
committerStephen Soltesz <soltesz@cs.princeton.edu>
Thu, 25 Jun 2009 23:01:59 +0000 (23:01 +0000)
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
web/MonitorWeb/monitorweb/static/css/style.css
web/MonitorWeb/monitorweb/static/xml/gadget.xml
web/MonitorWeb/monitorweb/static/xml/sitemonitor.xml
web/MonitorWeb/monitorweb/templates/links.py
web/MonitorWeb/monitorweb/templates/nodehistory.kid
web/MonitorWeb/monitorweb/templates/pcuhistory.kid
web/MonitorWeb/monitorweb/templates/sitehistory.kid
web/MonitorWeb/monitorweb/templates/sitesummary.kid [new file with mode: 0644]
web/MonitorWeb/monitorweb/templates/summary.kid [new file with mode: 0644]
web/MonitorWeb/monitorweb/templates/welcome.kid

index a1746c8..60bdbcc 100644 (file)
@@ -108,12 +108,16 @@ def prep_pcu_for_display(pcu):
 class NodeWidget(widgets.Widget):
        pass
 
 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:
        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)
                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())
 
                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------------------"
        @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)
 
                        # NOTE: reformat some fields.
                        agg = prep_node_for_display(node)
 
-                       #node.history.status
-                       #print node.hostname
-
                        if not agg.history:
                                continue
 
                        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:
                        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
                                
                                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)
                                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):
 
        @expose(template="monitorweb.templates.actionsummary")
        def actionsummary(self, since=7):
index d3a365c..ac85b33 100644 (file)
@@ -108,6 +108,9 @@ a.right { float: right; }
 #site-offline { background-color: red; }\r
 #site-down { background-color: indianred; }\r
 \r
 #site-offline { background-color: red; }\r
 #site-down { background-color: indianred; }\r
 \r
+#site-True { background-color : darkseagreen; }\r
+#site-False { background-color: indianred; }\r
+\r
 #node-online { background-color : lightgreen; }\r
 #node-good { background-color : darkseagreen; }\r
 #node-offline { background-color: red; }\r
 #node-online { background-color : lightgreen; }\r
 #node-good { background-color : darkseagreen; }\r
 #node-offline { background-color: red; }\r
@@ -118,7 +121,7 @@ a.right { float: right; }
 #pcu-offline { background-color: red; }\r
 #pcu-down { background-color: indianred; }\r
 \r
 #pcu-offline { background-color: red; }\r
 #pcu-down { background-color: indianred; }\r
 \r
-/*#site-0 { background-color : white; }*/\r
+#site-0 { background-color : darkseagreen ; }\r
 #site-1 { background-color: gold; }\r
 #site-2 { background-color: indianred; }\r
 \r
 #site-1 { background-color: gold; }\r
 #site-2 { background-color: indianred; }\r
 \r
index 8a3c79a..bae4356 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Module>
 <?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[
 <Require feature="dynamic-height"/>
 </ModulePrefs>
 <Content type="html"><![CDATA[
@@ -10,7 +10,7 @@ var displaycontent = function (responseText) {
        _gel('content_div').innerHTML = responseText; 
        _IG_AdjustIFrameHeight();
 };
        _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>
 </script>
 ]]></Content>
 </Module>
index 0bb0b02..2b2c4ad 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Module>
 <?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" 
                <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();
 };
        _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>
 _IG_FetchContent(url, displaycontent, { refreshInterval: 1200 }); 
 </script>
 ]]></Content>
index 95f192e..1a951bd 100644 (file)
@@ -2,6 +2,8 @@ from monitor import config
 import turbogears as tg
 import urllib
 
 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):
 def plc_mail_uri(ticketid):
        return config.RT_WEB_SERVER + "/Ticket/Display.html?id=" + str(ticketid)
 def plc_node_uri(hostname):
index de60dd9..e63d957 100644 (file)
@@ -18,37 +18,16 @@ from links import *
                <table id="sortable_table" class="datagrid" border="1" width="100%">
                        <thead>
                                <tr>
                <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>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'}" >
                                </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="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>
                                        <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>
index 79fd07b..d809609 100644 (file)
@@ -10,7 +10,7 @@ from links import *
          xmlns:mochi="http://www.mochi.org">
 
   <div py:match="item.tag == 'content'">
          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>
        <table width="100%">
                <tbody>
                <tr>
@@ -18,37 +18,16 @@ from links import *
                <table id="sortable_table" class="datagrid" border="1" width="100%">
                        <thead>
                                <tr>
                <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>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'}" >
                                </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="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>
                                        <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>
index 8dfb823..6040d83 100644 (file)
@@ -20,9 +20,10 @@ from links import *
                                <tr>
                                        <th mochi:format="int"></th>
                                        <th>Site name</th>
                                <tr>
                                        <th mochi:format="int"></th>
                                        <th>Site name</th>
+                                       <th mochi:format="int">Slices/Max</th>
                                        <th>Enabled</th>
                                        <th>Penalty</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>
                                        <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>
                                                        <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.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.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>
                                        <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 (file)
index 0000000..37e0541
--- /dev/null
@@ -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 (file)
index 0000000..27b888c
--- /dev/null
@@ -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>
index 43fdc21..af7b007 100644 (file)
@@ -1,4 +1,7 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r
+<?python\r
+from links import *\r
+?>\r
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#"\r
     py:extends="'master.kid'">\r
 <head>\r
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#"\r
     py:extends="'master.kid'">\r
 <head>\r
         <p> All nodes: <a href="node">Nodes</a> <br/> </p>\r
       </li>\r
     </ol>\r
         <p> All nodes: <a href="node">Nodes</a> <br/> </p>\r
       </li>\r
     </ol>\r
-    <!--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-->\r
+       <p>If you'd like to track things a little more informally, you can install\r
+       these Google Gadgets for summaries of the entire system or a specific\r
+       site.</p>\r
+    <ul class="links">\r
+      <li><a href="http://fusion.google.com/add?source=atgs&amp;moduleurl=${plc_myops_uri()}/monitor/gadget.xml">MyOps Summary</a></li>\r
+      <li><a href="http://fusion.google.com/add?source=atgs&amp;moduleurl=${plc_myops_uri()}/monitor/sitemonitor.xml">Site Summary</a></li>\r
+    </ul>\r
   </div>\r
   <!-- End of getting_started -->\r
 </body>\r
   </div>\r
   <!-- End of getting_started -->\r
 </body>\r