added advanced query
authorStephen Soltesz <soltesz@cs.princeton.edu>
Mon, 17 Aug 2009 21:49:31 +0000 (21:49 +0000)
committerStephen Soltesz <soltesz@cs.princeton.edu>
Mon, 17 Aug 2009 21:49:31 +0000 (21:49 +0000)
added simple and detailed view rather than single, 'pcuview'
simplified nodelist
clarified some labels
added error page for quickjumps without a target
added site:* and node:* queries for quickjump:
now you can see all sites that match a pattern:
    site:mlab*  or node:*clara*

13 files changed:
web/MonitorWeb/monitorweb/controllers.py
web/MonitorWeb/monitorweb/static/css/style.css
web/MonitorWeb/monitorweb/templates/detailview.kid
web/MonitorWeb/monitorweb/templates/node_template.kid
web/MonitorWeb/monitorweb/templates/nodefast.kid [new file with mode: 0644]
web/MonitorWeb/monitorweb/templates/nodelist.kid
web/MonitorWeb/monitorweb/templates/nodescanhistory.kid
web/MonitorWeb/monitorweb/templates/pculist.kid
web/MonitorWeb/monitorweb/templates/pcuview.kid
web/MonitorWeb/monitorweb/templates/query.kid [new file with mode: 0644]
web/MonitorWeb/monitorweb/templates/simpleview.kid
web/MonitorWeb/monitorweb/templates/sitelist.kid
web/MonitorWeb/monitorweb/templates/sitemenu.kid

index 1ce95cc..2821b76 100644 (file)
@@ -21,6 +21,67 @@ from monitor.wrapper.plccache import plcdb_hn2lb as site_hn2lb
 
 from monitorweb.templates.links import *
 
+class ObjectQueryFields(widgets.WidgetsList):
+       """The WidgetsList defines the fields of the form."""
+       pass
+
+
+
+class NodeQueryFields(widgets.WidgetsList):
+       """The WidgetsList defines the fields of the form."""
+
+       object = widgets.RadioButtonList(label="Query Type", options=[('nodes', 'All Nodes'), 
+                                                                                                                         ('nodehistory', 'Single Node History'),
+                                                                                                                         #('sites', 'All Sites'),
+                                                                                                                         #('sitehistory', 'Single Site History'),
+                                                                                                                         ], default="nodes")
+       nodehistory_hostname = widgets.TextField(label="Hostname Node History", attrs={'size':30})
+
+       hostname = widgets.CheckBox(label="Hostname")
+       firewall = widgets.CheckBox(label="Firewall?")
+       dns_status = widgets.CheckBox(label="DNS Status")
+       external_dns_status = widgets.CheckBox(label="Hostname Resolves?")
+       kernel_version = widgets.CheckBox(label="Kernel")
+       observed_status = widgets.CheckBox(label="Observed Status")
+       port_status = widgets.CheckBox(label="Port Status")
+       rpms = widgets.CheckBox(label="RPM")
+       rpmvalue = widgets.TextField(label="RPM Pattern")
+
+class QueryForm(widgets.TableForm):
+    template = """
+    <form xmlns:py="http://purl.org/kid/ns#"
+        name="${name}"
+        action="${action}"
+        method="${method}"
+        class="tableform"
+        py:attrs="form_attrs"
+    >
+        <div py:for="field in hidden_fields"
+            py:replace="field.display(value_for(field), **params_for(field))"
+        />
+        <table border="0" cellspacing="0" cellpadding="2" py:attrs="table_attrs">
+            <tr py:for="i, field in enumerate(fields)"
+                class="${i%2 and 'odd' or 'even'}"
+            >
+                <th>
+                    <label class="fieldlabel" for="${field.field_id}" py:content="field.label" />
+                </th>
+                <td>
+                    <span py:replace="field.display(value_for(field), **params_for(field))" />
+                    <span py:if="error_for(field)" class="fielderror" py:content="error_for(field)" />
+                    <span py:if="field.help_text" class="fieldhelp" py:content="field.help_text" />
+                </td>
+            </tr>
+            <tr>
+                <td>&#160;</td>
+                <td py:content="submit.display(submit_text)" />
+            </tr>
+        </table>
+    </form>
+       """
+
+def getNodeQueryForm():
+       return QueryForm(fields=NodeQueryFields(), action="query")
 
 # make it easier group objects without invoking the elixir auto-write feature.
 class aggregate: pass
@@ -110,6 +171,18 @@ def prep_pcu_for_display(pcu):
 class NodeWidget(widgets.Widget):
        pass
 
+def prep_nodehist(node):
+       agg = aggregate()
+       agg.node = node
+       agg.loginbase = "unknown"
+       try:
+               agg.loginbase = PlcSite.query.get(node.plc_siteid).plc_site_stats['login_base']
+       except:
+               agg.loginbase = "exception"
+               
+
+       return agg
+
 def prep_node_for_display(node, pcuhash=None, preppcu=True, asofdate=None):
        agg = aggregate()
        agg.node = node
@@ -214,33 +287,68 @@ class Root(controllers.RootController, MonitorXmlrpcServer):
                        agg = prep_node_for_display(fb)
                        rquery.append(agg)
 
-               #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
-#
-#                      if filter:
-#                              if agg.history.status == filter:
-#                                      query.append(agg)
-#                      else:
-#                              query.append(agg)
-                               
                widget = NodeWidget(template='monitorweb.templates.node_template')
                return dict(now=time.ctime(), query=rquery, nodewidget=widget)
 
+       @expose(template="monitorweb.templates.query", allow_json=True)
+       def query(self, **data):
+               query = []
+
+               for k in data:
+                       print k, data[k]
+
+               fbquery = None
+               
+               if 'object' in data and data['object'] == "nodes":
+                       fbquery = FindbadNodeRecord.get_all_latest()
+               elif 'object' in data and data['object'] == "nodehistory": 
+                       hostname = data['nodehistory_hostname']
+                       data['date_checked'] = 'date_checked'
+                       fbrecord = FindbadNodeRecord.get_by(hostname=hostname)
+                       fbquery = fbrecord.versions[-500:]
+
+               if fbquery:
+                       for node in fbquery:
+                               # NOTE: reformat some fields.
+                               if type(node) is not type(FindbadNodeRecord):
+                                       agg = node.__dict__.copy()
+                               else:
+                                       agg = node.to_dict()
+                               agg.update(agg['plc_node_stats'])
+                               if 'rpmvalue' in data and 'rpms' in data:
+                                       if agg['rpms']:
+                                               rpm_list = agg['rpms'].split()
+                                               rpm_list = filter(lambda x: data['rpmvalue'] in x, rpm_list)
+                                               agg['rpms'] = " ".join(rpm_list)
+
+                               query.append(agg)
+
+               fields=data.copy()
+
+               try: 
+                       del fields['object']
+                       del fields['rpmvalue']
+                       del fields['nodehistory_hostname']
+               except: pass
+               return dict(now=time.ctime(), query=query, fields=fields, data=data, queryform=getNodeQueryForm())
+
+       @expose(template="monitorweb.templates.nodefast", allow_json=True)
+       def node(self, filter=None):
+               nhquery = HistoryNodeRecord.query.all()
+               query = []
+               for nh in nhquery:
+                       if filter:
+                               if nh.status == filter:
+                                       agg = prep_nodehist(nh)
+                                       query.append(agg)
+                       else:
+                               agg = prep_nodehist(nh)
+                               query.append(agg)
+
+               return dict(now=time.ctime(), query=query)
+
        @expose(template="monitorweb.templates.nodelist")
-       def node(self, filter='boot'):
+       def nodeslow(self, filter='boot'):
                print "NODE------------------"
                print "befor-len: ", len( [ i for i in session] )
                session.flush(); session.clear()
@@ -365,23 +473,35 @@ class Root(controllers.RootController, MonitorXmlrpcServer):
                session.flush(); session.clear()
 
                loginbase=None
+               loginbase_list=[]
                hostname=None
                pcuid=None
                since=20
+               # if objtype is not None, then treat 'hostname' or 'loginbase' as a search pattern
+               objtype=None
 
                exceptions = None
                sitequery=[]
                nodequery=[]
                pcuquery=[]
                actions=[]
+               actions_list=[]
 
                for key in data:
                        print key, data[key]
 
                if 'query' in data:
                        obj = data['query']
-                       if len(obj.split(".")) > 1: hostname = obj
-                       else: loginbase=obj
+                       fields = obj.split(":")
+                       if len(fields) > 1:
+                               objtype = fields[0]
+                               obj = fields[1].replace("*", "%")
+                               print "obj: %s"% obj
+
+                       if len(obj.split(".")) > 1 or objtype == "node": 
+                               hostname = obj
+                       else: 
+                               loginbase = obj
 
                if 'loginbase' in data:
                        loginbase = data['loginbase']
@@ -400,32 +520,50 @@ class Root(controllers.RootController, MonitorXmlrpcServer):
                if pcuid:
                        print "pcuid: %s" % pcuid
                        pcu = FindbadPCURecord.get_latest_by(plc_pcuid=pcuid)
-                       loginbase = PlcSite.query.get(pcu.plc_pcu_stats['site_id']).plc_site_stats['login_base']
+                       loginbase_list += [ PlcSite.query.get(pcu.plc_pcu_stats['site_id']).plc_site_stats['login_base'] ]
 
                if hostname:
-                       node = FindbadNodeRecord.get_latest_by(hostname=hostname)
-                       loginbase = PlcSite.query.get(node.plc_node_stats['site_id']).plc_site_stats['login_base']
-
-               if loginbase:
-                       actions = ActionRecord.query.filter_by(loginbase=loginbase
-                                                       ).filter(ActionRecord.date_created >= datetime.now() - timedelta(since)
-                                                       ).order_by(ActionRecord.date_created.desc())
-                       actions = [ a for a in actions ]
-                       sitequery = [HistorySiteRecord.by_loginbase(loginbase)]
-                       # NOTE: because a single pcu may be assigned to multiple hosts,
-                       # track unique pcus by their plc_pcuid, then turn dict into list
-                       pcus = {}
-                       for node in FindbadNodeRecord.query.filter_by(loginbase=loginbase):
-                                       # NOTE: reformat some fields.
-                                       agg = prep_node_for_display(node)
-                                       nodequery += [agg]
-                                       if agg.pcu: 
-                                               pcus[agg.pcu.pcu.plc_pcuid] = agg.pcu
+                       if not objtype:
+                               nodes = [ FindbadNodeRecord.get_latest_by(hostname=hostname) ]
+                       else:
+                               nodes = FindbadNodeRecord.query.filter(FindbadNodeRecord.hostname.like(hostname)) 
 
-                       for pcuid_key in pcus:
-                               pcuquery += [pcus[pcuid_key]]
+                       for node in nodes:
+                               lb = PlcSite.query.get(node.plc_node_stats['site_id']).plc_site_stats['login_base']
+                               if lb not in loginbase_list:
+                                       loginbase_list += [ lb ]
 
-               return dict(sitequery=sitequery, pcuquery=pcuquery, nodequery=nodequery, actions=actions, since=since, exceptions=exceptions)
+               if loginbase:
+                       if not objtype:
+                               loginbase_list = [ loginbase ]
+                       else:
+                               loginbase_list = HistorySiteRecord.query.filter(HistorySiteRecord.loginbase.like(loginbase)) 
+                               loginbase_list = [ l.loginbase for l in loginbase_list ]
+                       
+
+               if loginbase_list:
+                       for loginbase in loginbase_list:
+                               actions = ActionRecord.query.filter_by(loginbase=loginbase
+                                                               ).filter(ActionRecord.date_created >= datetime.now() - timedelta(since)
+                                                               ).order_by(ActionRecord.date_created.desc())
+                               actions_list += [ a for a in actions ]
+                               site = HistorySiteRecord.by_loginbase(loginbase)
+                               if site:
+                                       sitequery.append(site)
+                               # NOTE: because a single pcu may be assigned to multiple hosts,
+                               # track unique pcus by their plc_pcuid, then turn dict into list
+                               pcus = {}
+                               for node in FindbadNodeRecord.query.filter_by(loginbase=loginbase):
+                                               # NOTE: reformat some fields.
+                                               agg = prep_node_for_display(node)
+                                               nodequery += [agg]
+                                               if agg.pcu: 
+                                                       pcus[agg.pcu.pcu.plc_pcuid] = agg.pcu
+
+                               for pcuid_key in pcus:
+                                       pcuquery += [pcus[pcuid_key]]
+
+               return dict(sitequery=sitequery, pcuquery=pcuquery, nodequery=nodequery, actions=actions_list, since=since, exceptions=exceptions)
 
 
        # TODO: add form validation
index ac85b33..71d6cca 100644 (file)
@@ -115,6 +115,9 @@ a.right { float: right; }
 #node-good { background-color : darkseagreen; }\r
 #node-offline { background-color: red; }\r
 #node-down { background-color: indianred; }\r
+#node-failboot { background-color: gold; }\r
+#node-safeboot { background-color: lightyellow; }\r
+#node-disabled { background-color: grey; }\r
 \r
 #pcu-online { background-color : lightgreen; }\r
 #pcu-good { background-color : darkseagreen; }\r
@@ -145,7 +148,7 @@ a.right { float: right; }
   color: black;\r
   font-size: 127%;\r
   background-color: white;\r
-  width: 757px;\r
+  /*width: 757px;*/\r
   margin: 0 auto 0 auto;\r
   border-left: 1px solid #aaa;\r
   border-right: 1px solid #aaa;\r
@@ -158,7 +161,7 @@ a.right { float: right; }
   margin: 0.5em;\r
   padding: 1em;\r
   float: right;\r
-  width: 200px;\r
+  /*width: 200px;*/\r
   font-size: 88%;\r
 }\r
 \r
@@ -209,7 +212,7 @@ h2 {
   padding: 10px;\r
   font-size: 80%;\r
   text-align: center;\r
-  width: 765px;\r
+  /*width: 765px;*/\r
   margin: 0 auto 1em auto;\r
 }\r
 \r
@@ -229,7 +232,7 @@ span.code {
   padding: 15px 10px 15px 55px;\r
   background: #cec URL('../images/ok.png') left center no-repeat;\r
   border: 1px solid #9c9;\r
-  width: 450px;\r
+  /*width: 450px;*/\r
   font-size: 120%;\r
   font-weight: bolder;\r
 }\r
@@ -237,14 +240,14 @@ span.code {
 .notice {\r
   margin: 0.5em auto 0.5em auto;\r
   padding: 15px 10px 15px 55px;\r
-  width: 450px;\r
+  /*width: 450px;*/\r
   background: #eef URL('../images/info.png') left center no-repeat;\r
   border: 1px solid #cce;\r
 }\r
 .error {\r
   margin: 0.5em auto 0.5em auto;\r
   padding: 15px 10px 15px 55px;\r
-  width: 450px;\r
+  /*width: 450px;*/\r
   background: #e30 URL('../images/widgets.png') left center no-repeat;\r
   border: 1px solid #c00;\r
 }\r
index 5881d98..e86bbb1 100644 (file)
@@ -145,16 +145,17 @@ from links import *
                                        <th>History (scan)</th>
                                        <th>Status Since</th>
                                        <th>Hostname</th>
-                                       <th>DNS</th>
+                                       <th>Resolves?</th>
                                        <th>SSH</th>
                                        <th>last_contact (cached)</th>
                                        <th>Last Checked</th>
                                        <th nowrap='true'>Port Status</th>
-                                       <th>Firewall</th>
+                                       <th>Blocked Ports?</th>
                                </tr>
                        </thead>
                        <tbody>
-                               <tr py:for="i,agg in enumerate(nodequery)" class="${i%2 and 'odd' or 'even'}" >
+                               <span py:for="i,agg in enumerate(nodequery)">
+                               <tr class="${i%2 and 'odd' or 'even'}" >
                                        <td><a href="nodehistory?hostname=${agg.node.hostname}">status</a>
                                                (<a href="nodescanhistory?hostname=${agg.node.hostname}">scan</a>)</td>
                                        <td id="site-${agg.history.status}" py:content="diff_time(mktime(agg.history.last_changed.timetuple()))"></td>
@@ -171,31 +172,23 @@ from links import *
                                                id="port${state}" py:content="'%s, ' % port">80</span>
                                        </td>
                                        <td py:content="agg.node.firewall"></td>
-                                       <td>
-                                               <!-- TODO: add some values/code to authenticate the operation.  -->
-                                               <!--form action="${link('pcuview', hostname=agg.node.hostname)}" name="externalscan${i}" method='post'>
-                                               <input type='hidden' name='hostname' value='${agg.node.hostname}'/> 
-                                               <input type='hidden' name='type' value='ExternalScan' /> 
-                                               </form>
-                                               <a onclick='document.externalscan${i}.submit();' href="javascript: void(1);">ExternalScan</a-->
-                                       </td>
-                                       <td>
-                                               <!-- TODO: add some values/code to authenticate the operation.  -->
-                                               <!--form action="${link('pcuview', hostname=agg.node.hostname)}" name="internalscan${i}" method='post'>
-                                               <input type='hidden' name='hostname' value='${agg.node.hostname}'/> 
-                                               <input type='hidden' name='type' value='InternalScan' /> 
-                                               </form>
-                                               <a onclick='javascript: document.internalscan${i}.submit();' href="javascript: void(1);">InternalScan</a-->
-                                       </td>
-                                       <td py:if="len(pcuquery) > 0">
-                                               <!-- TODO: add some values/code to authenticate the operation.  -->
-                                               <!--form action="${link('pcuview', pcuid=pcu.plc_pcuid)}" name="reboot${i}" method='post'>
-                                               <input type='hidden' name='hostname' value='${agg.node.hostname}'/> 
-                                               <input type='hidden' name='type' value='Reboot' /> 
-                                               </form>
-                                               <a onclick='javascript: document.reboot${i}.submit();' href="javascript: void(1);">Reboot</a-->
-                                       </td>
                                </tr>
+                               <tr>
+                                       <td></td>
+                                       <th>Kernel:</th>
+                                       <td colspan="3" py:content="agg.kernel"> </td>
+                               </tr>
+                               <tr>
+                                       <td></td>
+                                       <th>DNS Status:</th>
+                                       <td colspan="3"><pre py:content="agg.node.dns_status"> </pre></td>
+                               </tr>
+                               <tr>
+                                       <td></td>
+                                       <th>Traceroute:</th>
+                                       <td colspan="3"><pre py:content="agg.node.traceroute"> </pre></td>
+                               </tr>
+                               </span>
                        </tbody>
                </table>
                <div class="error" py:if="exceptions is not None">
index 3e1583a..c50a745 100644 (file)
@@ -18,7 +18,7 @@ from links import *
                <th>last_contact</th>
        </span>
        <span py:if="node is not None">
-                <td py:content="node.node.plc_node_stats['node_id']">node_id</td>
+        <td py:content="node.node.plc_node_stats['node_id']">node_id</td>
                <td nowrap="true">
                  <a target="_top" href="${link('pcuview', hostname=node.node.hostname)}" py:content="node.node.hostname">your.host.org</a></td>
                <td>
diff --git a/web/MonitorWeb/monitorweb/templates/nodefast.kid b/web/MonitorWeb/monitorweb/templates/nodefast.kid
new file mode 100644 (file)
index 0000000..97072d2
--- /dev/null
@@ -0,0 +1,75 @@
+<!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 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'">
+
+  <script type="text/javascript">
+    function nodelist_paginator(opts) { plekit_table_paginator(opts, "nodelist"); }
+  </script>
+
+  <center>
+  <b py:content="'BOOT: %d' % len([agg for agg in query if agg.node.status == 'good'])"></b> | 
+  <b py:content="'DOWN: %d' % len([agg for agg in query if agg.node.status == 'down'])"></b><br/>
+  </center>
+
+<table id="nodelist" cellpadding="0" border="0" class="plekit_table sortable-onload-2 colstyle-alt no-arrow paginationcallback-nodelist_paginator max-pages-10 paginate-25">
+  <thead>
+
+    <tr class='pagesize_area'><td class='pagesize_area' colspan='10'>
+        <form class='pagesize' action='satisfy_xhtml_validator'><fieldset>
+            <input class='pagesize_input' type='text' id="nodelist_pagesize" value='25'
+                   onkeyup='plekit_pagesize_set("nodelist","nodelist_pagesize", 25);' 
+                   size='3' maxlength='3' />                                                          
+            <label class='pagesize_label'> items/page </label>                                     
+            <img class='reset' src="/planetlab/icons/clear.png" alt="reset visible size"           
+                 onmousedown='plekit_pagesize_reset("nodelist","nodelist_pagesize", 999);' />
+    </fieldset></form></td></tr>                                                                        
+    
+    <tr class='search_area'><td class='search_area' colspan='10'>
+        <div class='search'><fieldset>
+            <label class='search_label'> Refine List </label>                 
+            <input class='search_input' type='text' id='nodelist_search' 
+                   onkeyup='plekit_table_filter("nodelist","nodelist_search","nodelist_search_and");'
+                   size='self.search_width' maxlength='256' />                                            
+            <label>and</label>                                                                        
+            <input id='nodelist_search_and' class='search_and'                                        
+                   type='checkbox' checked='checked'                                                      
+                   onchange='plekit_table_filter("nodelist","nodelist_search","nodelist_search_and");' />
+            <img class='reset' src="/planetlab/icons/clear.png" alt="reset search"
+                 onmousedown='plekit_table_filter_reset("nodelist","nodelist_search","nodelist_search_and");' />
+    </fieldset></div></td></tr>
+    
+    <tr>
+      <th class="sortable plekit_table">ID</th>
+      <th class="sortable plekit_table">Site</th>
+      <th class="sortable plekit_table">Hostname</th>
+      <th class="sortable plekit_table">Status</th>
+      <th class="sortable-sortLastContact plekit_table">Last Changed</th>
+      <th class="sortable plekit_table">Firewall</th>
+  </tr>
+  </thead>
+  <tbody>
+    <tr py:for="i,agg in enumerate(query)">
+        <td py:content="agg.node.plc_nodeid">node_id</td>
+               <td> <a href="${link('simpleview', loginbase=agg.loginbase)}">${agg.loginbase}</a> </td>
+               <td nowrap="true"> <a target="_top" href="${link('simpleview', hostname=agg.node.hostname)}" py:content="agg.node.hostname">your.host.org</a></td>
+        <td py:content="agg.node.status">boot</td>
+               <td  id="node-${agg.node.status}" py:content="diff_time(mktime(agg.node.last_changed.timetuple()))"></td>
+               <td nowrap="true" py:content="agg.node.firewall"></td>
+    </tr>
+
+  </tbody>  
+</table>
+
+</div>
+
+</html>
index 4f4425a..e32b92d 100644 (file)
@@ -36,7 +36,7 @@ from links import *
     
     <tr class='search_area'><td class='search_area' colspan='10'>
         <div class='search'><fieldset>
-            <label class='search_label'> Search </label>                 
+            <label class='search_label'> Refine List</label>                 
             <input class='search_input' type='text' id='nodelist_search' 
                    onkeyup='plekit_table_filter("nodelist","nodelist_search","nodelist_search_and");'
                    size='self.search_width' maxlength='256' />                                            
index 03416e7..3c9f84b 100644 (file)
@@ -42,7 +42,7 @@ from cherrypy import request, response
     
     <tr class='search_area'><td class='search_area' colspan='10'>
         <div class='search'><fieldset>
-            <label class='search_label'> Search </label>                 
+            <label class='search_label'> Refine List </label>                 
             <input class='search_input' type='text' id='nodelist_search' 
                    onkeyup='plekit_table_filter("nodelist","nodelist_search","nodelist_search_and");'
                    size='self.search_width' maxlength='256' />                                            
index e9f8cdc..eb67141 100644 (file)
@@ -32,7 +32,7 @@ from links import *
     
     <tr class='search_area'><td class='search_area' colspan='5'>
         <div class='search'><fieldset>
-            <label class='search_label'> Search </label>                 
+            <label class='search_label'> Refine List</label>                 
             <input class='search_input' type='text' id='pculist_search' 
                    onkeyup='plekit_table_filter("pculist","pculist_search","pculist_search_and");'
                    size='self.search_width' maxlength='256' />                                            
@@ -57,14 +57,14 @@ from links import *
     <tr py:for="i,node in enumerate(query)">
       <td nowrap='true'>
        <div class='oneline'>
-         <a class='left' href="${link('pcuview', loginbase=node.loginbase)}">${node.loginbase}</a>
+         <a class='left' href="${link('simpleview', loginbase=node.loginbase)}">${node.loginbase}</a>
          <a class='right' href="${plc_site_uri_id(node.pcu.plc_pcu_stats['site_id'])}">
            <img style='display: inline' border='0' src="static/images/extlink.gif" align='right'/></a>
        </div>
       </td>
       <td nowrap='true'>
        <div class='oneline'>
-         <a class='left' href="${link('pcuview', pcuid=node.pcu.plc_pcuid)}">${pcu_name(node.pcu.plc_pcu_stats)}</a>
+         <a class='left' href="${link('simpleview', pcuid=node.pcu.plc_pcuid)}">${pcu_name(node.pcu.plc_pcu_stats)}</a>
          <a class='right' href="${plc_pcu_uri_id(node.pcu.plc_pcu_stats['pcu_id'])}">
            <img style='display: inline' border='0' src="static/images/extlink.gif" align='right'/></a>
        </div>
@@ -76,10 +76,10 @@ from links import *
       <td width="20%" nowrap='true' align='center' id="status-${node.status}">
        <div id="links">
          <a class="info" py:if="'error' in node.status" 
-            href="${link('pcuview', pcuid=node.pcu.plc_pcuid)}">
+            href="${link('simpleview', pcuid=node.pcu.plc_pcuid)}">
            Error<span><pre>${node.pcu.reboot_trial_status}</pre></span></a>
          <a py:if="'error' not in node.status" 
-            href="${link('pcuview', pcuid=node.pcu.plc_pcuid)}"
+            href="${link('simpleview', pcuid=node.pcu.plc_pcuid)}"
             py:content="node.status">Reboot Status</a>
        </div>
       </td>
index bd6fa58..832b9a4 100644 (file)
@@ -145,11 +145,11 @@ from links import *
                                        <th mochi:format="int"></th>
                                        <th>History (scan)</th>
                                        <th>Hostname</th>
-                                       <th>DNS</th>
+                                       <th>Resolves?</th>
                                        <th>last_contact (cached)</th>
                                        <th>last_checked</th>
                                        <th nowrap='true'>Port Status</th>
-                                       <th>Filter</th>
+                                       <th>Blocked Ports?</th>
                                        <th></th>
                                        <th></th>
                                </tr>
diff --git a/web/MonitorWeb/monitorweb/templates/query.kid b/web/MonitorWeb/monitorweb/templates/query.kid
new file mode 100644 (file)
index 0000000..c44202a
--- /dev/null
@@ -0,0 +1,63 @@
+<!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 py:layout="'sitemenu.kid'"
+      xmlns:py="http://purl.org/kid/ns#"
+         xmlns:mochi="http://www.mochi.org">
+
+  <div py:match="item.tag == 'content'">
+               <h2>Functional, but Under Development...</h2>
+               <table>
+                       <tr>
+                               <td>${queryform.display(method="GET", value=data)}</td>
+                       </tr>
+               </table>
+<h4>Results</h4>
+       <table py:if="fields and len(fields.keys()) > 0" id="querylist" cellpadding="0" border="0" class="plekit_table sortable-onload-0 colstyle-alt no-arrow paginationcallback-querylist_paginator max-pages-10 paginate-50" width="100%">
+       <thead>
+       <tr class='pagesize_area'><td class='pagesize_area' colspan='5'>
+                <form class='pagesize' action='satisfy_xhtml_validator'><fieldset>
+            <input class='pagesize_input' type='text' id="querylist_pagesize" value='50'
+                   onkeyup='plekit_pagesize_set("querylist","querylist_pagesize", 50);' 
+                   size='3' maxlength='3' />                                                          
+            <label class='pagesize_label'> items/page </label>                                     
+            <img class='reset' src="/planetlab/icons/clear.png" alt="reset visible size"           
+                 onmousedown='plekit_pagesize_reset("querylist","querylist_pagesize", 999);' />
+       </fieldset></form></td></tr>                                                                        
+       <tr class='search_area'><td class='search_area' colspan='5'>
+        <div class='search'><fieldset>
+            <label class='search_label'> Search </label>                 
+            <input class='search_input' type='text' id='querylist_search' 
+                   onkeyup='plekit_table_filter("querylist","querylist_search","querylist_search_and");'
+                   size='self.search_width' maxlength='256' />                                            
+            <label>and</label>                                                                        
+            <input id='querylist_search_and' class='search_and'                                        
+                   type='checkbox' checked='checked'                                                      
+                   onchange='plekit_table_filter("querylist","querylist_search","querylist_search_and");' />
+            <img class='reset' src="/planetlab/icons/clear.png" alt="reset search"
+                 onmousedown='plekit_table_filter_reset("querylist","querylist_search","querylist_search_and");' />
+       </fieldset></div></td></tr>
+               <!-- for keys show each th -->
+               <tr>
+                       <span py:for="key in sorted(fields.keys())" >
+                               <th class="sortable plekit_table">${key}</th>
+                       </span>
+               </tr>
+       </thead>
+       <tbody>
+               <!-- for keys show value -->
+               <tr py:for="row in query"  >
+                       <span py:for="key in sorted(fields.keys())" >
+                               <td>${row[key]}</td>
+                       </span>
+               </tr>
+      </tbody>
+       </table>
+  </div>
+</html>
index 2d6190e..5077501 100644 (file)
@@ -12,6 +12,18 @@ from links import *
          xmlns:mochi="http://www.mochi.org">
 
   <div py:match="item.tag == 'content'">
+  <div py:if="len(sitequery) == 0">
+       <p>Your 'quick jump' query failed to find a matching site or hostname.</p>
+       <p>MyOps recognizes three types of expressions:
+       <ul>
+           <li>Site names, e.g. princeton, utah, nyu, etc</li>
+           <li>Host names, e.g. planetlab-1.cs.princeton.edu, pl1.university.edu, etc</li>
+           <li>Prefix a pattern with "site:" or "node:" to return all sites or
+               nodes that match a pattern.  e.g. site:mlab* node:*redclara*</li>
+       </ul>
+       </p>
+  </div>
+  <div py:if="len(sitequery) != 0">
     <h3 py:if="len(sitequery) > 0">Site Status</h3>
                <table py:if="len(sitequery) > 0" id="sub-table" border="1" width="100%">
                        <thead>
@@ -56,12 +68,12 @@ from links import *
                                        </td>
                                        <td py:content="agg.pcu.plc_pcu_stats['model']"></td>
                                        <td py:content="len(agg.pcu.plc_pcu_stats['node_ids'])"></td>
-                                       <td nowrap="true" width="70em"><a href="${link('detailview', loginbase=site.loginbase)}">More Details</a></td>
+                                       <td nowrap="true" width="70em"><a href="${link('detailview', pcuid=agg.pcu.plc_pcuid)}">More Details</a></td>
                                </tr>
                        </tbody>
                </table>
        <div class="oneline" id="legend" py:if="len(pcuquery) == 0">
-               <em>There are no PCUs associated with this host.</em>
+               <h3>PCUs: None</h3>
        </div>
        <h3>Nodes</h3> 
                <p py:if="len(nodequery) == 0">
@@ -83,7 +95,7 @@ from links import *
                                                        <span class="icon">${agg.node.hostname}</span></a>
                                        </td>
                                        <td py:content="diff_time(mktime(agg.node.date_checked.timetuple()))"></td>
-                                       <td nowrap="true" width="70em"><a href="${link('detailview', loginbase=site.loginbase)}">More Details</a></td>
+                                       <td nowrap="true" width="70em"><a href="${link('detailview', hostname=agg.node.hostname)}">More Details</a></td>
                                </tr>
                        </tbody>
                </table>
@@ -177,6 +189,7 @@ from links import *
                        </span>
                </div-->
 
+     </div>
   </div>
 
 </html>
index ae136a6..116defc 100644 (file)
@@ -31,7 +31,7 @@ from links import *
     
     <tr class='search_area'><td class='search_area' colspan='6'>
         <div class='search'><fieldset>
-            <label class='search_label'> Search </label>                 
+            <label class='search_label'> Refine List </label>                 
             <input class='search_input' type='text' id='sitelist_search' 
                    onkeyup='plekit_table_filter("sitelist","sitelist_search","sitelist_search_and");'
                    size='self.search_width' maxlength='256' />                                            
@@ -56,7 +56,7 @@ from links import *
     <tr py:for="i,site in enumerate(query)">
       <td nowrap="true">
        <div class='oneline'>
-         <a class='left' href="${link('pcuview', loginbase=site.loginbase)}">${site.loginbase}</a>
+         <a class='left' href="${link('simpleview', loginbase=site.loginbase)}">${site.loginbase}</a>
          <a class='right' href="${plc_site_uri_id(site.plc_siteid)}">
            <img style='display: inline' border='0' src="static/images/extlink.gif" align='right'/></a>
        </div>
index d62be8d..70e532d 100644 (file)
        <table valign="top" border="1" bgcolor="white" align="center">
        <tr> <td> <div id="header">${page_title}</div> </td> 
                <td>
-                       <form action="pcuview" method="GET"> 
+                       <form action="simpleview" method="GET"> 
                                <table>
-                                       <tr><td> Quick Search:</td>
+                                       <tr><td> Quick Jump:</td>
                                                <td><input type="text" name="query"/></td>
                                                <td><input type="submit"/></td>
+                                               <td><a href="query">Advanced Query</a></td>
                                        </tr>
                                </table>
                        </form>