basic display of nodes, pcus, and sites.
authorStephen Soltesz <soltesz@cs.princeton.edu>
Tue, 2 Dec 2008 19:31:20 +0000 (19:31 +0000)
committerStephen Soltesz <soltesz@cs.princeton.edu>
Tue, 2 Dec 2008 19:31:20 +0000 (19:31 +0000)
updates to various files needed to enable this.

12 files changed:
monitor/database/info/history.py
monitor/util/__init__.py
monitor/wrapper/plccache.py
sitebad.py
web/MonitorWeb/dev.cfg
web/MonitorWeb/monitorweb/controllers.py
web/MonitorWeb/monitorweb/model.py
web/MonitorWeb/monitorweb/static/css/style.css
web/MonitorWeb/monitorweb/templates/nodelist.kid
web/MonitorWeb/monitorweb/templates/pculist.kid
web/MonitorWeb/monitorweb/templates/sitemenu.kid
web/MonitorWeb/prod.cfg [new file with mode: 0644]

index c871c78..dc53860 100644 (file)
@@ -40,8 +40,14 @@ class HistorySiteRecord(Entity):
 
        nodes_total = Field(Int,default=0)
        nodes_up = Field(Int,default=0)
 
        nodes_total = Field(Int,default=0)
        nodes_up = Field(Int,default=0)
+       slices_total = Field(Int,default=0)
        slices_used = Field(Int,default=0)
 
        slices_used = Field(Int,default=0)
 
+       # all nodes offline and never-contact.
+       new = Field(Boolean,default=False)
+
+       enabled = Field(Boolean,default=False)
+
        status = Field(String,default="unknown")
 
        @classmethod
        status = Field(String,default="unknown")
 
        @classmethod
index f204047..8986f7f 100644 (file)
@@ -1 +1,34 @@
 __all__=["writepid","removepid","daemonize"]
 __all__=["writepid","removepid","daemonize"]
+
+import time
+import math
+
+def diff_time(timestamp, abstime=True):
+       now = time.time()
+       if timestamp == None:
+               return "unknown"
+       if abstime:
+               diff = now - timestamp
+       else:
+               diff = timestamp
+       # return the number of seconds as a difference from current time.
+       t_str = ""
+       if diff < 60: # sec in min.
+               t = diff / 1
+               t_str = "%s sec ago" % int(math.ceil(t))
+       elif diff < 60*60: # sec in hour
+               t = diff / (60)
+               t_str = "%s min ago" % int(math.ceil(t))
+       elif diff < 60*60*24: # sec in day
+               t = diff / (60*60)
+               t_str = "%s hrs ago" % int(math.ceil(t))
+       elif diff < 60*60*24*14: # sec in week
+               t = diff / (60*60*24)
+               t_str = "%s days ago" % int(math.ceil(t))
+       elif diff <= 60*60*24*30: # approx sec in month
+               t = diff / (60*60*24*7)
+               t_str = "%s wks ago" % int(math.ceil(t))
+       elif diff > 60*60*24*30: # approx sec in month
+               t = diff / (60*60*24*30)
+               t_str = "%s mnths ago" % int(t)
+       return t_str
index 978e6bb..d4cfbbc 100755 (executable)
@@ -87,7 +87,7 @@ def init():
        api = plc.getCachedAuthAPI()
        l_sites = api.GetSites({'peer_id':None}, 
                                                        ['login_base', 'site_id', 'abbreviated_name', 'latitude', 
        api = plc.getCachedAuthAPI()
        l_sites = api.GetSites({'peer_id':None}, 
                                                        ['login_base', 'site_id', 'abbreviated_name', 'latitude', 
-                                                       'longitude', 'max_slices', 'slice_ids', 'node_ids' ])
+                                                       'longitude', 'max_slices', 'slice_ids', 'node_ids', 'enabled' ])
        l_nodes = api.GetNodes({'peer_id':None}, 
                                                        ['hostname', 'node_id', 'ports', 'site_id', 'version', 'last_updated', 
                                                         'date_created', 'last_contact', 'pcu_ids', 'nodenetwork_ids'])
        l_nodes = api.GetNodes({'peer_id':None}, 
                                                        ['hostname', 'node_id', 'ports', 'site_id', 'version', 'last_updated', 
                                                         'date_created', 'last_contact', 'pcu_ids', 'nodenetwork_ids'])
index 12ae8c8..781cab6 100755 (executable)
@@ -10,7 +10,7 @@ from monitor import database
 from pcucontrol  import reboot
 from monitor import parser as parsermodule
 from monitor import config
 from pcucontrol  import reboot
 from monitor import parser as parsermodule
 from monitor import config
-from monitor.database import HistorySiteRecord, FindbadNodeRecord
+from monitor.database.info.model import HistorySiteRecord, FindbadNodeRecord, session
 from monitor.wrapper import plc, plccache
 from monitor.const import MINUP
 
 from monitor.wrapper import plc, plccache
 from monitor.const import MINUP
 
@@ -32,6 +32,19 @@ def main(config):
        
        checkAndRecordState(l_sites, l_plcsites)
 
        
        checkAndRecordState(l_sites, l_plcsites)
 
+def getnewsite(nodelist):
+       new = True
+       for node in nodelist:
+               try:
+                       noderec = FindbadNodeRecord.query.filter(FindbadNodeRecord.hostname==node['hostname']).order_by(FindbadNodeRecord.date_checked.desc()).first()
+                       if noderec is not None and \
+                               noderec.plc_node_stats['last_contact'] != None:
+                               new = False
+               except:
+                       import traceback
+                       print traceback.print_exc()
+       return new
+
 def getnodesup(nodelist):
        up = 0
        for node in nodelist:
 def getnodesup(nodelist):
        up = 0
        for node in nodelist:
@@ -62,9 +75,12 @@ def checkAndRecordState(l_sites, l_plcsites):
                        pf = HistorySiteRecord.findby_or_create(loginbase=sitename)
 
                        pf.last_checked = datetime.now()
                        pf = HistorySiteRecord.findby_or_create(loginbase=sitename)
 
                        pf.last_checked = datetime.now()
+                       pf.slices_total = d_site['max_slices']
                        pf.slices_used = len(d_site['slice_ids'])
                        pf.nodes_total = len(lb2hn[sitename])
                        pf.nodes_up = getnodesup(lb2hn[sitename])
                        pf.slices_used = len(d_site['slice_ids'])
                        pf.nodes_total = len(lb2hn[sitename])
                        pf.nodes_up = getnodesup(lb2hn[sitename])
+                       pf.new = getnewsite(lb2hn[sitename])
+                       pf.enabled = d_site['enabled']
 
                        if pf.nodes_up >= MINUP:
                                if pf.status != "good": pf.last_changed = datetime.now()
 
                        if pf.nodes_up >= MINUP:
                                if pf.status != "good": pf.last_changed = datetime.now()
@@ -76,7 +92,10 @@ def checkAndRecordState(l_sites, l_plcsites):
                        count += 1
                        print "%d %15s slices(%2s) nodes(%2s) up(%2s) %s" % (count, sitename, pf.slices_used, 
                                                                                        pf.nodes_total, pf.nodes_up, pf.status)
                        count += 1
                        print "%d %15s slices(%2s) nodes(%2s) up(%2s) %s" % (count, sitename, pf.slices_used, 
                                                                                        pf.nodes_total, pf.nodes_up, pf.status)
+                       pf.flush()
+
        print HistorySiteRecord.query.count()
        print HistorySiteRecord.query.count()
+       session.flush()
 
        return True
 
 
        return True
 
index f1e675b..d5915c7 100644 (file)
@@ -30,12 +30,12 @@ server.environment="development"
 autoreload.package="monitorweb"
 
 
 autoreload.package="monitorweb"
 
 
-server.socket_host="127.0.0.1"
+server.socket_host="monitor.planet-lab.org"
 server.socket_port=8080
 server.socket_port=8080
-server.webpath="/monitor/"
-base_url_filter.on = False
-base_url_filter.base_url = "http://127.0.0.1:8080/monitor"
-base_url_filter.use_x_forwarded_host = True
+#server.webpath="/monitor/"
+#base_url_filter.on = False
+#base_url_filter.base_url = "http://127.0.0.1:8080/monitor"
+#base_url_filter.use_x_forwarded_host = True
 
 # Auto-Reload after code modification
 # autoreload.on = True
 
 # Auto-Reload after code modification
 # autoreload.on = True
index d2978da..d4553dc 100644 (file)
@@ -51,14 +51,18 @@ class Root(controllers.RootController):
                                        node.pcu_status = pcu.reboot_trial_status
                                else:
                                        node.pcu_status = "nodata"
                                        node.pcu_status = pcu.reboot_trial_status
                                else:
                                        node.pcu_status = "nodata"
+                               node.pcu_short_status = format_pcu_shortstatus(pcu)
+
                        else:
                                node.pcu_status = "nopcu"
                        else:
                                node.pcu_status = "nopcu"
+                               node.pcu_short_status = "none"
 
                        if node.kernel_version:
                                node.kernel = node.kernel_version.split()[2]
                        else:
                                node.kernel = ""
 
 
                        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
                        # NOTE: count filters
                        if node.observed_status != 'DOWN':
                                filtercount[node.observed_status] += 1
@@ -102,7 +106,6 @@ class Root(controllers.RootController):
                        else:
                                filtercount['pending'] += 1
                                
                        else:
                                filtercount['pending'] += 1
                                
-                       print reboot.pcu_name(node.plc_pcu_stats)
                        node.ports = format_ports(node)
                        node.status = format_pcu_shortstatus(node)
 
                        node.ports = format_ports(node)
                        node.status = format_pcu_shortstatus(node)
 
@@ -123,10 +126,32 @@ class Root(controllers.RootController):
                                
                return dict(query=query, fc=filtercount)
 
                                
                return dict(query=query, fc=filtercount)
 
-       @expose(template="monitorweb.templates.pculist")
+       @expose(template="monitorweb.templates.sitelist")
        def site(self, filter='all'):
        def site(self, filter='all'):
-               filtercount = {'ok' : 0, 'NetDown': 0, 'Not_Run' : 0, 'pending' : 0, 'all' : 0}
-               return dict(query=[], fc=filtercount)
+               filtercount = {'good' : 0, 'down': 0, 'new' : 0, 'pending' : 0, 'all' : 0}
+               fbquery = HistorySiteRecord.query.all()
+               query = []
+               for site in fbquery:
+                       # count filter
+                       filtercount['all'] += 1
+                       if site.new and site.slices_used == 0 and not site.enabled:
+                               filtercount['new'] += 1
+                       elif not site.enabled:
+                               filtercount['pending'] += 1
+                       else:
+                               filtercount[site.status] += 1
+
+                       # apply filter
+                       if filter == "all":
+                               query.append(site)
+                       elif filter == 'new' and site.new and site.slices_used == 0 and not site.enabled:
+                               query.append(site)
+                       elif filter == "pending" and not site.enabled:
+                               query.append(site)
+                       elif filter == site.status:
+                               query.append(site)
+                               
+               return dict(query=query, fc=filtercount)
 
        @expose(template="monitorweb.templates.pculist")
        def action(self, filter='all'):
 
        @expose(template="monitorweb.templates.pculist")
        def action(self, filter='all'):
index b570416..f3fda87 100644 (file)
@@ -11,6 +11,7 @@ from elixir import String, Unicode, Integer, DateTime
 
 options_defaults['autosetup'] = False
 
 
 options_defaults['autosetup'] = False
 
+from monitor.database.info.model import *
 
 # your data model
 
 
 # your data model
 
index 59053a2..072c484 100644 (file)
@@ -10,18 +10,20 @@ html, body {
   padding: 0;\r
 }\r
 \r
   padding: 0;\r
 }\r
 \r
-td, th {padding:2px;border:none;}\r
+td, th {padding:1px;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
 \r
 #header {\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
 \r
 #header {\r
-  height: 80px;\r
-  width: 777px;\r
-  background: blue URL('../images/header_inner.png') no-repeat;\r
+  height: 40px;\r
+  width: 780px;\r
+  /*background: blue URL('../images/header_inner.png') no-repeat;*/\r
   border-left: 1px solid #aaa;\r
   border-right: 1px solid #aaa;\r
   margin: 0 auto 0 auto;\r
   border-left: 1px solid #aaa;\r
   border-right: 1px solid #aaa;\r
   margin: 0 auto 0 auto;\r
+  text-align: center;\r
+  font-size: 180%;\r
 }\r
 \r
 a.link, a, a.active {\r
 }\r
 \r
 a.link, a, a.active {\r
@@ -42,7 +44,16 @@ a.link, a, a.active {
 #status-Not_Run  { background-color: lightgrey; }\r
 #status-ok     { background-color: darkseagreen; }\r
 #status-0     { background-color: darkseagreen; }\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
+#status-error  { background-color: indianred; }\r
+#status-none   { background-color: white; }\r
+\r
+#site-good { background-color : darkseagreen; }\r
+#site-down { background-color: indianred; }\r
+\r
+/*#nps-table { background-color: lightgrey; }*/\r
+/*#sub-table { background-color: lightgrey; }*/\r
+/* td, th {padding:2px;border:none;} */\r
+/* tr th {text-align:left;background-color:#f0f0f0;color:#333;} */\r
 \r
 #main_content {\r
   color: black;\r
 \r
 #main_content {\r
   color: black;\r
@@ -112,7 +123,7 @@ h2 {
   padding: 10px;\r
   font-size: 80%;\r
   text-align: center;\r
   padding: 10px;\r
   font-size: 80%;\r
   text-align: center;\r
-  width: 757px;\r
+  width: 765px;\r
   margin: 0 auto 1em auto;\r
 }\r
 \r
   margin: 0 auto 1em auto;\r
 }\r
 \r
index dc3bf92..5e5dec1 100644 (file)
@@ -1,6 +1,8 @@
 <!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"
 <!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"
+from monitor.util import diff_time
+from time import mktime
 ?>
 <html py:layout="'sitemenu.kid'"
       xmlns:py="http://purl.org/kid/ns#">
 ?>
 <html py:layout="'sitemenu.kid'"
       xmlns:py="http://purl.org/kid/ns#">
@@ -20,12 +22,12 @@ layout_params['page_title'] = "Monitor Node View"
                <tbody>
                <tr>
                <td colspan="5">
                <tbody>
                <tr>
                <td colspan="5">
-               <table border="1">
+               <table id="sub-table" border="1" width="100%">
                        <thead>
                                <tr>
                                        <th>Hostname</th>
                                        <th>ping</th>
                        <thead>
                                <tr>
                                        <th>Hostname</th>
                                        <th>ping</th>
-                                       <th>ssh</th>
+                                       <!--th>ssh</th-->
                                        <th>pcu</th>
                                        <th>status</th>
                                        <th>kernel</th>
                                        <th>pcu</th>
                                        <th>status</th>
                                        <th>kernel</th>
@@ -36,11 +38,11 @@ layout_params['page_title'] = "Monitor Node View"
                                <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>
                                <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.ssh_status"></td-->
+                                 <td id="status-${node.pcu_short_status}" py:content="node.pcu_short_status"></td>
                                  <td py:content="node.observed_status"></td>
                                  <td nowrap="true" py:content="node.kernel"></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>
+                                 <td py:content="diff_time(node.plc_node_stats['last_contact'])"></td>
                                </tr>
                        </tbody>
                </table>
                                </tr>
                        </tbody>
                </table>
index fc1b835..1ca6e36 100644 (file)
@@ -15,7 +15,7 @@ def pcu_link(pcu):
       xmlns:py="http://purl.org/kid/ns#">
 
   <div py:match="item.tag == 'content'">
       xmlns:py="http://purl.org/kid/ns#">
 
   <div py:match="item.tag == 'content'">
-       <table width="100%">
+       <table id="sub-table" width="100%">
                <thead>
                        <tr>
                                <th><a href="${tg.url('pcu', filter='ok')}">Ok(${fc['ok']})</a></th>
                <thead>
                        <tr>
                                <th><a href="${tg.url('pcu', filter='ok')}">Ok(${fc['ok']})</a></th>
@@ -28,7 +28,7 @@ def pcu_link(pcu):
                <tbody>
                <tr>
                <td colspan="5">
                <tbody>
                <tr>
                <td colspan="5">
-               <table border="1">
+               <table border="1" width="100%">
                        <thead>
                                <tr>
                                        <th>Site</th>
                        <thead>
                                <tr>
                                        <th>Site</th>
@@ -52,7 +52,7 @@ def pcu_link(pcu):
                                                <span py:for="port,state in node.ports" 
                                                id="port${state}" py:content="'%s, ' % port">80</span>
                                        </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 width="40" 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>
                                        <td py:content="node.plc_pcu_stats['model']"></td>
                                        <td py:content="len(node.plc_pcu_stats['node_ids'])"></td>
                                </tr>
index 23e9d41..d46e500 100644 (file)
@@ -6,11 +6,11 @@
   </head>
 
   <body>
   </head>
 
   <body>
-    <h1>Monitor : ${page_title}</h1>
-       <table valign="top" border="1" bgcolor="white" align="center" width="800">
+    <div id="header">Monitor : ${page_title}</div>
+       <table valign="top" border="1" bgcolor="white" align="center" width="60em">
        <tr>
                <td>
        <tr>
                <td>
-                       <table>
+                       <table id="nps-table" width="100%">
                        <thead>
                        <tr>
                                <th><a href="${tg.url('node')}">Nodes</a></th>
                        <thead>
                        <tr>
                                <th><a href="${tg.url('node')}">Nodes</a></th>
@@ -32,6 +32,6 @@
        </tr>
        </table>
 
        </tr>
        </table>
 
-    <div class="footer">Copywrite XYZ</div>
+    <div id="footer">Copywrite © 2007-2008 The Trustees of Princeton University</div>
   </body>
 </html>
   </body>
 </html>
diff --git a/web/MonitorWeb/prod.cfg b/web/MonitorWeb/prod.cfg
new file mode 100644 (file)
index 0000000..f1e675b
--- /dev/null
@@ -0,0 +1,76 @@
+[global]
+# This is where all of your settings go for your development environment
+# Settings that are the same for both development and production
+# (such as template engine, encodings, etc.) all go in
+# monitorweb/config/app.cfg
+
+# DATABASE
+
+# driver://username:password@host:port/database
+
+# pick the form for your database
+# sqlalchemy.dburi="postgres://username@hostname/databasename"
+# sqlalchemy.dburi="mysql://username:password@hostname:port/databasename"
+# sqlalchemy.dburi="sqlite://%(current_dir_uri)s/devdata.sqlite"
+
+# If you have sqlite, here's a simple default to get you started
+# in development
+sqlalchemy.dburi="sqlite:///devdata.sqlite"
+
+
+# SERVER
+
+# Some server parameters that you may want to tweak
+# server.socket_port=8080
+
+# Enable the debug output at the end on pages.
+# log_debug_info_filter.on = False
+
+server.environment="development"
+autoreload.package="monitorweb"
+
+
+server.socket_host="127.0.0.1"
+server.socket_port=8080
+server.webpath="/monitor/"
+base_url_filter.on = False
+base_url_filter.base_url = "http://127.0.0.1:8080/monitor"
+base_url_filter.use_x_forwarded_host = True
+
+# Auto-Reload after code modification
+# autoreload.on = True
+
+# Set to True if you'd like to abort execution if a controller gets an
+# unexpected parameter. False by default
+tg.strict_parameters = True
+
+# LOGGING
+# Logging configuration generally follows the style of the standard
+# Python logging module configuration. Note that when specifying
+# log format messages, you need to use *() for formatting variables.
+# Deployment independent log configuration is in monitorweb/config/log.cfg
+[logging]
+
+[[loggers]]
+[[[monitorweb]]]
+level='DEBUG'
+qualname='monitorweb'
+handlers=['debug_out']
+
+[[[allinfo]]]
+level='INFO'
+handlers=['debug_out']
+
+[[[access]]]
+level='INFO'
+qualname='turbogears.access'
+handlers=['access_out']
+propagate=0
+
+
+[[[database]]]
+# Set to INFO to make SQLAlchemy display SQL commands
+level='ERROR'
+qualname='sqlalchemy.engine'
+handlers=['debug_out']
+propagate=0