supports basic listing of pcus, nodes, and some coloring from the old scripts.
authorStephen Soltesz <soltesz@cs.princeton.edu>
Mon, 1 Dec 2008 21:58:16 +0000 (21:58 +0000)
committerStephen Soltesz <soltesz@cs.princeton.edu>
Mon, 1 Dec 2008 21:58:16 +0000 (21:58 +0000)
web/MonitorWeb/monitorweb/controllers.py
web/MonitorWeb/monitorweb/static/css/style.css
web/MonitorWeb/monitorweb/templates/nodelist.kid [new file with mode: 0644]
web/MonitorWeb/monitorweb/templates/pculist.kid [new file with mode: 0644]
web/MonitorWeb/monitorweb/templates/sitemenu.kid [new file with mode: 0644]

index 8d9ced5..d2978da 100644 (file)
@@ -3,11 +3,132 @@ from turbogears import controllers, expose, flash
 # from monitorweb import model
 # import logging
 # log = logging.getLogger("monitorweb.controllers")
+from monitor.database.info.model import *
+from pcucontrol import reboot
+
+def format_ports(pcu):
+       retval = []
+       if pcu.port_status and len(pcu.port_status.keys()) > 0 :
+               obj = reboot.model_to_object(pcu.plc_pcu_stats['model'])
+               for port in obj.supported_ports:
+                       state = pcu.port_status[str(port)]
+                       retval.append( (port, state) )
+
+       if retval == []: 
+               retval = [( "Closed/Filtered", "state" )]
+
+       return retval
+
+def format_pcu_shortstatus(pcu):
+       status = "error"
+       if pcu.reboot_trial_status == str(0):
+               status = "ok"
+       elif pcu.reboot_trial_status == "NetDown" or pcu.reboot_trial_status == "Not_Run":
+               status = pcu.reboot_trial_status
+       else:
+               status = "error"
+
+       return status
 
 class Root(controllers.RootController):
-    @expose(template="monitorweb.templates.welcome")
-    def index(self):
-        import time
-        # log.debug("Happy TurboGears Controller Responding For Duty")
-        flash("Your application is now running")
-        return dict(now=time.ctime())
+       @expose(template="monitorweb.templates.welcome")
+       def index(self):
+               import time
+               # log.debug("Happy TurboGears Controller Responding For Duty")
+               flash("Your application is now running")
+               return dict(now=time.ctime())
+
+       @expose(template="monitorweb.templates.nodelist")
+       def node(self, filter='BOOT'):
+               import time
+               fbquery = FindbadNodeRecord.get_all_latest()
+               query = []
+               filtercount = {'DOWN' : 0, 'BOOT': 0, 'DEBUG' : 0, 'neverboot' : 0, 'pending' : 0, 'all' : 0}
+               for node in fbquery:
+                       if node.plc_pcuid:
+                               pcu = FindbadPCURecord.get_latest_by(plc_pcuid=node.plc_pcuid).first()
+                               if pcu:
+                                       node.pcu_status = pcu.reboot_trial_status
+                               else:
+                                       node.pcu_status = "nodata"
+                       else:
+                               node.pcu_status = "nopcu"
+
+                       if node.kernel_version:
+                               node.kernel = node.kernel_version.split()[2]
+                       else:
+                               node.kernel = ""
+
+                       # NOTE: count filters
+                       if node.observed_status != 'DOWN':
+                               filtercount[node.observed_status] += 1
+                       else:
+                               if node.plc_node_stats['last_contact'] != None:
+                                       filtercount[node.observed_status] += 1
+                               else:
+                                       filtercount['neverboot'] += 1
+
+                       # NOTE: apply filter
+                       if filter == node.observed_status:
+                               if filter == "DOWN":
+                                       if node.plc_node_stats['last_contact'] != None:
+                                               query.append(node)
+                               else:
+                                       query.append(node)
+                       elif filter == "neverboot":
+                               if node.plc_node_stats['last_contact'] == None:
+                                       query.append(node)
+                       elif filter == "pending":
+                               # TODO: look in message logs...
+                               pass
+                       elif filter == "all":
+                               query.append(node)
+                               
+               return dict(now=time.ctime(), query=query, fc=filtercount)
+
+       @expose(template="monitorweb.templates.pculist")
+       def pcu(self, filter='all'):
+               import time
+               fbquery = FindbadPCURecord.get_all_latest()
+               query = []
+               filtercount = {'ok' : 0, 'NetDown': 0, 'Not_Run' : 0, 'pending' : 0, 'all' : 0}
+               for node in fbquery:
+
+                       # NOTE: count filter
+                       if node.reboot_trial_status == str(0):
+                               filtercount['ok'] += 1
+                       elif node.reboot_trial_status == 'NetDown' or node.reboot_trial_status == 'Not_Run':
+                               filtercount[node.reboot_trial_status] += 1
+                       else:
+                               filtercount['pending'] += 1
+                               
+                       print reboot.pcu_name(node.plc_pcu_stats)
+                       node.ports = format_ports(node)
+                       node.status = format_pcu_shortstatus(node)
+
+                       # NOTE: apply filter
+                       if filter == "all":
+                               query.append(node)
+                       elif filter == "ok" and node.reboot_trial_status == str(0):
+                               query.append(node)
+                       elif filter == node.reboot_trial_status:
+                               query.append(node)
+                       elif filter == "pending":
+                               # TODO: look in message logs...
+                               if node.reboot_trial_status != str(0) and \
+                                       node.reboot_trial_status != 'NetDown' and \
+                                       node.reboot_trial_status != 'Not_Run':
+
+                                       query.append(node)
+                               
+               return dict(query=query, fc=filtercount)
+
+       @expose(template="monitorweb.templates.pculist")
+       def site(self, filter='all'):
+               filtercount = {'ok' : 0, 'NetDown': 0, 'Not_Run' : 0, 'pending' : 0, 'all' : 0}
+               return dict(query=[], fc=filtercount)
+
+       @expose(template="monitorweb.templates.pculist")
+       def action(self, filter='all'):
+               filtercount = {'ok' : 0, 'NetDown': 0, 'Not_Run' : 0, 'pending' : 0, 'all' : 0}
+               return dict(query=[], fc=filtercount)
index c98d40e..59053a2 100644 (file)
@@ -10,7 +10,7 @@ html, body {
   padding: 0;\r
 }\r
 \r
-td, th {padding:3px;border:none;}\r
+td, th {padding:2px;border:none;}\r
 tr th {text-align:left;background-color:#f0f0f0;color:#333;}\r
 tr.odd td {background-color:#edf3fe;}\r
 tr.even td {background-color:#fff;}\r
@@ -28,6 +28,21 @@ a.link, a, a.active {
   color: #369;\r
 }\r
 \r
+#portopen     { background-color: lightgreen; }\r
+#portclosed   { background-color: indianred; }\r
+#portfiltered { background-color: gold; }\r
+\r
+#dns-DNS-OK { background-color: lightgreen; }\r
+#dns-NOHOSTNAME { background-color: white; }\r
+#dns-DNS-MISMATCH { background-color: gold; }\r
+#dns-DNS-NOENTRY { background-color: indianred; }\r
+#dns-NO-DNS-OR-IP { background-color: indianred; }\r
+\r
+#status-NetDown { background-color: lightgrey; }\r
+#status-Not_Run  { background-color: lightgrey; }\r
+#status-ok     { background-color: darkseagreen; }\r
+#status-0     { background-color: darkseagreen; }\r
+#status-error  { background-color: indianred; width="200px"; }\r
 \r
 #main_content {\r
   color: black;\r
@@ -131,4 +146,4 @@ span.code {
 .fielderror {\r
     color: red;\r
     font-weight: bold;\r
-}
\ No newline at end of file
+}\r
diff --git a/web/MonitorWeb/monitorweb/templates/nodelist.kid b/web/MonitorWeb/monitorweb/templates/nodelist.kid
new file mode 100644 (file)
index 0000000..dc3bf92
--- /dev/null
@@ -0,0 +1,53 @@
+<!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'] = "Monitor Node View"
+?>
+<html py:layout="'sitemenu.kid'"
+      xmlns:py="http://purl.org/kid/ns#">
+
+  <div py:match="item.tag == 'content'">
+       <table width="100%">
+               <thead>
+                       <tr>
+                               <th><a href="${tg.url('node', filter='BOOT')}">Production(${fc['BOOT']})</a></th>
+                               <th><a href="${tg.url('node', filter='DEBUG')}">Debug(${fc['DEBUG']})</a></th>
+                               <th><a href="${tg.url('node', filter='DOWN')}">Down(${fc['DOWN']})</a></th>
+                               <th><a href="${tg.url('node', filter='neverboot')}">Never Booted(${fc['neverboot']})</a></th>
+                               <th><a href="${tg.url('node', filter='pending')}">Pending Reply(${fc['pending']})</a></th>
+                               <th><a href="${tg.url('node', filter='all')}">All</a></th>
+                       </tr>
+               </thead>
+               <tbody>
+               <tr>
+               <td colspan="5">
+               <table border="1">
+                       <thead>
+                               <tr>
+                                       <th>Hostname</th>
+                                       <th>ping</th>
+                                       <th>ssh</th>
+                                       <th>pcu</th>
+                                       <th>status</th>
+                                       <th>kernel</th>
+                                       <th>last_contact</th>
+                               </tr>
+                       </thead>
+                       <tbody>
+                               <tr py:for="i,node in enumerate(query)" class="${i%2 and 'odd' or 'even'}" >
+                                 <td nowrap="true" py:content="node.hostname"></td>
+                                 <td py:content="node.ping_status"></td>
+                                 <td py:content="node.ssh_status"></td>
+                                 <td py:content="node.pcu_status"></td>
+                                 <td py:content="node.observed_status"></td>
+                                 <td nowrap="true" py:content="node.kernel"></td>
+                                 <td py:content="node.plc_node_stats['last_contact']"></td>
+                               </tr>
+                       </tbody>
+               </table>
+               </td>
+               </tr>
+               </tbody>
+       </table>
+  </div>
+
+</html>
diff --git a/web/MonitorWeb/monitorweb/templates/pculist.kid b/web/MonitorWeb/monitorweb/templates/pculist.kid
new file mode 100644 (file)
index 0000000..fc1b835
--- /dev/null
@@ -0,0 +1,67 @@
+<!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'] = "Monitor PCU View"
+from pcucontrol.reboot import pcu_name, model_to_object
+from monitor import config
+
+def plc_site_link(pcu):
+       return "https://" + config.MONITOR_HOSTNAME + "/db/sites/index.php?id=" + str(pcu['site_id'])
+
+def pcu_link(pcu):
+       return "https://" + config.MONITOR_HOSTNAME + "/db/sites/pcu.php?id=" + str(pcu['pcu_id'])
+
+?>
+<html py:layout="'sitemenu.kid'"
+      xmlns:py="http://purl.org/kid/ns#">
+
+  <div py:match="item.tag == 'content'">
+       <table width="100%">
+               <thead>
+                       <tr>
+                               <th><a href="${tg.url('pcu', filter='ok')}">Ok(${fc['ok']})</a></th>
+                               <th><a href="${tg.url('pcu', filter='Not_Run')}">Misconfigured(${fc['Not_Run']})</a></th>
+                               <th><a href="${tg.url('pcu', filter='NetDown')}">Offline(${fc['NetDown']})</a></th>
+                               <th><a href="${tg.url('pcu', filter='pending')}">Runtime Error(${fc['pending']})</a></th>
+                               <th><a href="${tg.url('pcu', filter='all')}">All</a></th>
+                       </tr>
+               </thead>
+               <tbody>
+               <tr>
+               <td colspan="5">
+               <table border="1">
+                       <thead>
+                               <tr>
+                                       <th>Site</th>
+                                       <th>PCU Name</th>
+                                       <th>Missing Fields</th>
+                                       <th>DNS Status</th>
+                                       <th>Port Status</th>
+                                       <th width="80%">Test Results</th>
+                                       <th>Model</th>
+                                       <th>Nodes</th>
+                               </tr>
+                       </thead>
+                       <tbody>
+                               <tr py:for="i,node in enumerate(query)" class="${i%2 and 'odd' or 'even'}" >
+                                       <td><a href="${plc_site_link(node.plc_pcu_stats)}">sitename</a></td>
+                                       <td nowrap="true" >
+                                               <a href="${pcu_link(node.plc_pcu_stats)}">${pcu_name(node.plc_pcu_stats)}</a></td>
+                                       <td py:content="node.entry_complete"></td>
+                                       <td id="dns-${node.dns_status}" py:content="node.dns_status"></td>
+                                       <td>
+                                               <span py:for="port,state in node.ports" 
+                                               id="port${state}" py:content="'%s, ' % port">80</span>
+                                       </td>
+                                       <td id="status-${node.status}" py:content="node.reboot_trial_status"></td>
+                                       <td py:content="node.plc_pcu_stats['model']"></td>
+                                       <td py:content="len(node.plc_pcu_stats['node_ids'])"></td>
+                               </tr>
+                       </tbody>
+               </table>
+               </td>
+               </tr>
+               </tbody>
+       </table>
+  </div>
+
+</html>
diff --git a/web/MonitorWeb/monitorweb/templates/sitemenu.kid b/web/MonitorWeb/monitorweb/templates/sitemenu.kid
new file mode 100644 (file)
index 0000000..23e9d41
--- /dev/null
@@ -0,0 +1,37 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns:py="http://purl.org/kid/ns#">
+  <head>
+    <title>App Name - ${page_title}</title>
+    <link href="/static/css/style.css" type="text/css" rel="stylesheet" />
+  </head>
+
+  <body>
+    <h1>Monitor : ${page_title}</h1>
+       <table valign="top" border="1" bgcolor="white" align="center" width="800">
+       <tr>
+               <td>
+                       <table>
+                       <thead>
+                       <tr>
+                               <th><a href="${tg.url('node')}">Nodes</a></th>
+                               <th><a href="${tg.url('pcu')}">PCUs</a></th>
+                               <th><a href="${tg.url('site')}">Sites</a></th>
+                               <th><a href="${tg.url('action')}">Actions</a></th>
+                       </tr>
+                       </thead>
+                       <tbody>
+                       <tr>
+                               <td colspan="4">
+                               <content>Default content - this will be replaced by an element marked with 
+                                       py:match="item.tag == 'content'"</content>
+                               </td>
+                       </tr>
+                       </tbody>
+                       </table>
+               </td>
+       </tr>
+       </table>
+
+    <div class="footer">Copywrite XYZ</div>
+  </body>
+</html>