From: Stephen Soltesz <soltesz@cs.princeton.edu>
Date: Tue, 2 Dec 2008 19:31:20 +0000 (+0000)
Subject: basic display of nodes, pcus, and sites.
X-Git-Tag: Monitor-2.0-0~24
X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=d8616c5bab940943ef8a17db7937a5eb733dd526;p=monitor.git

basic display of nodes, pcus, and sites.
updates to various files needed to enable this.
---

diff --git a/monitor/database/info/history.py b/monitor/database/info/history.py
index c871c78..dc53860 100644
--- a/monitor/database/info/history.py
+++ b/monitor/database/info/history.py
@@ -40,8 +40,14 @@ class HistorySiteRecord(Entity):
 
 	nodes_total = Field(Int,default=0)
 	nodes_up = Field(Int,default=0)
+	slices_total = 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
diff --git a/monitor/util/__init__.py b/monitor/util/__init__.py
index f204047..8986f7f 100644
--- a/monitor/util/__init__.py
+++ b/monitor/util/__init__.py
@@ -1 +1,34 @@
 __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
diff --git a/monitor/wrapper/plccache.py b/monitor/wrapper/plccache.py
index 978e6bb..d4cfbbc 100755
--- a/monitor/wrapper/plccache.py
+++ b/monitor/wrapper/plccache.py
@@ -87,7 +87,7 @@ def init():
 	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'])
diff --git a/sitebad.py b/sitebad.py
index 12ae8c8..781cab6 100755
--- a/sitebad.py
+++ b/sitebad.py
@@ -10,7 +10,7 @@ from monitor import database
 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
 
@@ -32,6 +32,19 @@ def main(config):
 	
 	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:
@@ -62,9 +75,12 @@ def checkAndRecordState(l_sites, l_plcsites):
 			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.new = getnewsite(lb2hn[sitename])
+			pf.enabled = d_site['enabled']
 
 			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)
+			pf.flush()
+
 	print HistorySiteRecord.query.count()
+	session.flush()
 
 	return True
 
diff --git a/web/MonitorWeb/dev.cfg b/web/MonitorWeb/dev.cfg
index f1e675b..d5915c7 100644
--- a/web/MonitorWeb/dev.cfg
+++ b/web/MonitorWeb/dev.cfg
@@ -30,12 +30,12 @@ server.environment="development"
 autoreload.package="monitorweb"
 
 
-server.socket_host="127.0.0.1"
+server.socket_host="monitor.planet-lab.org"
 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
diff --git a/web/MonitorWeb/monitorweb/controllers.py b/web/MonitorWeb/monitorweb/controllers.py
index d2978da..d4553dc 100644
--- a/web/MonitorWeb/monitorweb/controllers.py
+++ b/web/MonitorWeb/monitorweb/controllers.py
@@ -51,14 +51,18 @@ class Root(controllers.RootController):
 					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"
+				node.pcu_short_status = "none"
 
 			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
@@ -102,7 +106,6 @@ class Root(controllers.RootController):
 			else:
 				filtercount['pending'] += 1
 				
-			print reboot.pcu_name(node.plc_pcu_stats)
 			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)
 
-	@expose(template="monitorweb.templates.pculist")
+	@expose(template="monitorweb.templates.sitelist")
 	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'):
diff --git a/web/MonitorWeb/monitorweb/model.py b/web/MonitorWeb/monitorweb/model.py
index b570416..f3fda87 100644
--- a/web/MonitorWeb/monitorweb/model.py
+++ b/web/MonitorWeb/monitorweb/model.py
@@ -11,6 +11,7 @@ from elixir import String, Unicode, Integer, DateTime
 
 options_defaults['autosetup'] = False
 
+from monitor.database.info.model import *
 
 # your data model
 
diff --git a/web/MonitorWeb/monitorweb/static/css/style.css b/web/MonitorWeb/monitorweb/static/css/style.css
index 59053a2..072c484 100644
--- a/web/MonitorWeb/monitorweb/static/css/style.css
+++ b/web/MonitorWeb/monitorweb/static/css/style.css
@@ -10,18 +10,20 @@ html, body {
   padding: 0;
 }
 
-td, th {padding:2px;border:none;}
+td, th {padding:1px;border:none;}
 tr th {text-align:left;background-color:#f0f0f0;color:#333;}
 tr.odd td {background-color:#edf3fe;}
 tr.even td {background-color:#fff;}
 
 #header {
-  height: 80px;
-  width: 777px;
-  background: blue URL('../images/header_inner.png') no-repeat;
+  height: 40px;
+  width: 780px;
+  /*background: blue URL('../images/header_inner.png') no-repeat;*/
   border-left: 1px solid #aaa;
   border-right: 1px solid #aaa;
   margin: 0 auto 0 auto;
+  text-align: center;
+  font-size: 180%;
 }
 
 a.link, a, a.active {
@@ -42,7 +44,16 @@ a.link, a, a.active {
 #status-Not_Run  { background-color: lightgrey; }
 #status-ok     { background-color: darkseagreen; }
 #status-0     { background-color: darkseagreen; }
-#status-error  { background-color: indianred; width="200px"; }
+#status-error  { background-color: indianred; }
+#status-none   { background-color: white; }
+
+#site-good { background-color : darkseagreen; }
+#site-down { background-color: indianred; }
+
+/*#nps-table { background-color: lightgrey; }*/
+/*#sub-table { background-color: lightgrey; }*/
+/* td, th {padding:2px;border:none;} */
+/* tr th {text-align:left;background-color:#f0f0f0;color:#333;} */
 
 #main_content {
   color: black;
@@ -112,7 +123,7 @@ h2 {
   padding: 10px;
   font-size: 80%;
   text-align: center;
-  width: 757px;
+  width: 765px;
   margin: 0 auto 1em auto;
 }
 
diff --git a/web/MonitorWeb/monitorweb/templates/nodelist.kid b/web/MonitorWeb/monitorweb/templates/nodelist.kid
index dc3bf92..5e5dec1 100644
--- a/web/MonitorWeb/monitorweb/templates/nodelist.kid
+++ b/web/MonitorWeb/monitorweb/templates/nodelist.kid
@@ -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"
+from monitor.util import diff_time
+from time import mktime
 ?>
 <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">
-		<table border="1">
+		<table id="sub-table" border="1" width="100%">
 			<thead>
 				<tr>
 					<th>Hostname</th>
 					<th>ping</th>
-					<th>ssh</th>
+					<!--th>ssh</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>
-				  <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.plc_node_stats['last_contact']"></td>
+				  <td py:content="diff_time(node.plc_node_stats['last_contact'])"></td>
 				</tr>
 			</tbody>
 		</table>
diff --git a/web/MonitorWeb/monitorweb/templates/pculist.kid b/web/MonitorWeb/monitorweb/templates/pculist.kid
index fc1b835..1ca6e36 100644
--- a/web/MonitorWeb/monitorweb/templates/pculist.kid
+++ b/web/MonitorWeb/monitorweb/templates/pculist.kid
@@ -15,7 +15,7 @@ def pcu_link(pcu):
       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>
@@ -28,7 +28,7 @@ def pcu_link(pcu):
 		<tbody>
 		<tr>
 		<td colspan="5">
-		<table border="1">
+		<table border="1" width="100%">
 			<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>
-					<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>
diff --git a/web/MonitorWeb/monitorweb/templates/sitemenu.kid b/web/MonitorWeb/monitorweb/templates/sitemenu.kid
index 23e9d41..d46e500 100644
--- a/web/MonitorWeb/monitorweb/templates/sitemenu.kid
+++ b/web/MonitorWeb/monitorweb/templates/sitemenu.kid
@@ -6,11 +6,11 @@
   </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>
-			<table>
+			<table id="nps-table" width="100%">
 			<thead>
 			<tr>
 				<th><a href="${tg.url('node')}">Nodes</a></th>
@@ -32,6 +32,6 @@
 	</tr>
   	</table>
 
-    <div class="footer">Copywrite XYZ</div>
+    <div id="footer">Copywrite © 2007-2008 The Trustees of Princeton University</div>
   </body>
 </html>
diff --git a/web/MonitorWeb/prod.cfg b/web/MonitorWeb/prod.cfg
new file mode 100644
index 0000000..f1e675b
--- /dev/null
+++ b/web/MonitorWeb/prod.cfg
@@ -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