added xmlrpc calls for applying and removing penalties to sites
authorStephen Soltesz <soltesz@cs.princeton.edu>
Sat, 4 Apr 2009 00:29:19 +0000 (00:29 +0000)
committerStephen Soltesz <soltesz@cs.princeton.edu>
Sat, 4 Apr 2009 00:29:19 +0000 (00:29 +0000)
added views for site and node histories.

web/MonitorWeb/monitorweb/monitor_xmlrpc.py [new file with mode: 0644]
web/MonitorWeb/monitorweb/templates/nodehistory.kid [new file with mode: 0644]
web/MonitorWeb/monitorweb/templates/sitehistory.kid [new file with mode: 0644]

diff --git a/web/MonitorWeb/monitorweb/monitor_xmlrpc.py b/web/MonitorWeb/monitorweb/monitor_xmlrpc.py
new file mode 100644 (file)
index 0000000..a0c5052
--- /dev/null
@@ -0,0 +1,161 @@
+import sys
+import xmlrpclib
+import cherrypy
+import turbogears
+from datetime import datetime, timedelta
+import time
+
+from monitor.database.info.model import *
+from monitor.database.info.interface import *
+
+class MonitorXmlrpcServerMethods:
+       @cherrypy.expose
+       def listMethods(self):
+               mod = MonitorXmlrpcServer()
+               ret_list = []
+               for f in dir(mod):
+                       if isinstance(mod.__getattribute__(f),type(mod.__getattribute__('addDowntime'))):
+                               ret_list += [f]
+               return ret_list
+
+def convert_datetime(d, keys=None):
+       ret = d.copy()
+       n = datetime.now()
+       if keys == None:
+               keys = d.keys()
+       for k in keys:
+               if type(d[k]) == type(n):
+                       ret[k] = time.mktime(d[k].utctimetuple())
+       
+       return ret
+
+class MonitorXmlrpcServer(object):
+
+       @cherrypy.expose
+       def listMethods(self):
+               mod = MonitorXmlrpcServer()
+               ret_list = []
+               for f in dir(mod):
+                       if isinstance(mod.__getattribute__(f),type(mod.__getattribute__('addDowntime'))):
+                               ret_list += [f]
+               return ret_list
+
+       @turbogears.expose()
+       def XMLRPC(self):
+               params, method = xmlrpclib.loads(cherrypy.request.body.read())
+               try:
+                       if method == "xmlrpc":
+                               # prevent recursion
+                               raise AssertionError("method cannot be 'xmlrpc'")
+                       # Get the function and make sure it's exposed.
+                       method = getattr(self, method, None)
+                       # Use the same error message to hide private method names
+                       if method is None or not getattr(method, "exposed", False):
+                               raise AssertionError("method does not exist")
+
+                       session.clear()
+                       # Call the method, convert it into a 1-element tuple
+                       # as expected by dumps                                     
+                       response = method(*params)
+
+                       session.flush()
+                       response = xmlrpclib.dumps((response,), methodresponse=1, allow_none=1)
+               except xmlrpclib.Fault, fault:
+                       # Can't marshal the result
+                       response = xmlrpclib.dumps(fault, allow_none=1)
+               except:
+                       # Some other error; send back some error info
+                       response = xmlrpclib.dumps(
+                               xmlrpclib.Fault(1, "%s:%s" % (sys.exc_type, sys.exc_value))
+                               )
+
+               cherrypy.response.headers["Content-Type"] = "text/xml"
+               return response
+
+       # User-defined functions must use cherrypy.expose; turbogears.expose
+       #       does additional checking of the response type that we don't want.
+       @cherrypy.expose
+       def upAndRunning(self):
+               return True
+
+       # SITES ------------------------------------------------------------
+
+       @cherrypy.expose
+       def getSiteStatus(self, auth):
+               ret_list = []
+               sites = HistorySiteRecord.query.all()
+               for q in sites:
+                       d = q.to_dict(exclude=['timestamp', 'version', ])
+                       d = convert_datetime(d, ['last_checked', 'last_changed', 'message_created'])
+                       ret_list.append(d)
+               return ret_list
+
+       @cherrypy.expose
+       def clearSitePenalty(self, auth, loginbase):
+               sitehist = SiteInterface.get_or_make(loginbase=loginbase)
+               sitehist.clearPenalty()
+               #sitehist.applyPenalty()
+               #sitehist.sendMessage('clear_penalty')
+               sitehist.closeTicket()
+               return True
+
+       @cherrypy.expose
+       def increaseSitePenalty(self, auth, loginbase):
+               sitehist = SiteInterface.get_or_make(loginbase=loginbase)
+               sitehist.increasePenalty()
+               #sitehist.applyPenalty()
+               #sitehist.sendMessage('increase_penalty')
+               return True
+
+       # NODES ------------------------------------------------------------
+
+       @cherrypy.expose
+       def getNodeStatus(self, auth):
+               ret_list = []
+               sites = HistoryNodeRecord.query.all()
+               for q in sites:
+                       d = q.to_dict(exclude=['timestamp', 'version', ])
+                       d = convert_datetime(d, ['last_checked', 'last_changed',])
+                       ret_list.append(d)
+               return ret_list
+
+       @cherrypy.expose
+       def getRecentActions(self, auth, loginbase=None, hostname=None):
+               ret_list = []
+               return ret_list
+
+       # BLACKLIST ------------------------------------------------------------
+
+       @cherrypy.expose
+       def getBlacklist(self, auth):
+               bl = BlacklistRecord.query.all()
+               ret_list = []
+               for q in bl:
+                       d = q.to_dict(exclude=['timestamp', 'version', 'id', ])
+                       d = convert_datetime(d, ['date_created'])
+                       ret_list.append(d)
+
+               return ret_list
+               # datetime.datetime.fromtimestamp(time.mktime(time.strptime(mytime, time_format)))
+       
+       @cherrypy.expose
+       def addHostToBlacklist(self, auth, hostname, expires=0):
+               bl = BlacklistRecord.findby_or_create(hostname=hostname, expires=expires)
+               return True
+
+       @cherrypy.expose
+       def addSiteToBlacklist(self, auth, loginbase, expires=0):
+               bl = BlacklistRecord.findby_or_create(hostname=hostname, expires=expires)
+               return True
+
+       @cherrypy.expose
+       def deleteFromBlacklist(self, auth, loginbase=None, hostname=None):
+               if (loginbase==None and hostname == None) or (loginbase != None and hostname != None):
+                       raise Exception("Please specify a single record to delete: either hostname or loginbase")
+               elif loginbase != None:
+                       bl = BlacklistRecord.get_by(loginbase=loginbase)
+                       bl.delete()
+               elif hostname != None:
+                       bl = BlacklistRecord.get_by(hostname=hostname)
+                       bl.delete()
+               return True
diff --git a/web/MonitorWeb/monitorweb/templates/nodehistory.kid b/web/MonitorWeb/monitorweb/templates/nodehistory.kid
new file mode 100644 (file)
index 0000000..8fa825b
--- /dev/null
@@ -0,0 +1,60 @@
+<!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 List"
+from monitor.util import diff_time
+from time import mktime
+from links import *
+?>
+<html py:layout="'sitemenu.kid'"
+      xmlns:py="http://purl.org/kid/ns#"
+         xmlns:mochi="http://www.mochi.org">
+
+  <div py:match="item.tag == 'content'">
+       <h3>Node History : ${hostname}</h3>
+       <table width="100%">
+               <tbody>
+               <tr>
+               <td>
+               <table id="sortable_table" class="datagrid" border="1" width="100%">
+                       <thead>
+                               <tr>
+                                       <th mochi:format="int"></th>
+                                       <!--th>Site</th>
+                                       <th>pcu</th-->
+                                       <th>Hostname</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></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>
+                               </tr>
+                       </tbody>
+               </table>
+               </td>
+               </tr>
+               </tbody>
+       </table>
+  </div>
+
+</html>
diff --git a/web/MonitorWeb/monitorweb/templates/sitehistory.kid b/web/MonitorWeb/monitorweb/templates/sitehistory.kid
new file mode 100644 (file)
index 0000000..66cc0d1
--- /dev/null
@@ -0,0 +1,55 @@
+<!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 Site History List"
+from monitor.util import diff_time
+from time import mktime
+from links import *
+?>
+<html py:layout="'sitemenu.kid'"
+      xmlns:py="http://purl.org/kid/ns#"
+         xmlns:mochi="http://www.mochi.org">
+
+  <div py:match="item.tag == 'content'">
+       <h3>Site History : ${loginbase}</h3>
+       <table width="100%">
+               <tbody>
+               <tr>
+               <td>
+               <table id="sortable_table" class="datagrid" border="1" width="100%">
+                       <thead>
+                               <tr>
+                                       <th mochi:format="int"></th>
+                                       <th>Site name</th>
+                                       <th>Enabled</th>
+                                       <th>Penalty</th>
+                                       <th mochi:format="int">Slices/Max</th>
+                                       <th mochi:format="int">Nodes/Total</th>
+                                       <th>Date Checked</th>
+                               </tr>
+                       </thead>
+                       <tbody>
+                               <tr py:for="i,site in enumerate(query)" class="${i%2 and 'odd' or 'even'}" >
+                                       <td></td>
+                                       <td nowrap="true">
+                                               <div class='oneline'>
+                                               <a class='left' href="${link('pcuview', loginbase=site.loginbase)}">${site.loginbase}</a>
+                                               <a class='right' href="${plc_site_uri(site.loginbase)}">
+                                                       <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.status}" py:content="diff_time(mktime(site.last_changed.timetuple()))"></td>
+                                       <td py:content="site.timestamp"></td>
+                               </tr>
+                       </tbody>
+               </table>
+               </td>
+               </tr>
+               </tbody>
+       </table>
+  </div>
+
+</html>