rhmessaging commits: r3177 - mgmt/trunk/wooly/python/wooly.
by rhmessaging-commits@lists.jboss.org
Author: justi9
Date: 2009-03-19 13:39:04 -0400 (Thu, 19 Mar 2009)
New Revision: 3177
Modified:
mgmt/trunk/wooly/python/wooly/parameters.py
Log:
Remove the unused set_element_parameter method of ListParameter, and rename item param member.
Modified: mgmt/trunk/wooly/python/wooly/parameters.py
===================================================================
--- mgmt/trunk/wooly/python/wooly/parameters.py 2009-03-19 16:00:42 UTC (rev 3176)
+++ mgmt/trunk/wooly/python/wooly/parameters.py 2009-03-19 17:39:04 UTC (rev 3177)
@@ -51,18 +51,14 @@
self.default = dict()
class ListParameter(Parameter):
- def __init__(self, app, name, param):
+ def __init__(self, app, name, item_parameter):
super(ListParameter, self).__init__(app, name)
- self.param = param
+ self.item_parameter = item_parameter
self.default = list()
self.is_collection = True
- # XXX eliminate
- def set_element_parameter(self, param):
- self.param = param
-
def get_default(self, session):
return copy(self.default)
@@ -72,10 +68,10 @@
return lst
def do_unmarshal(self, string):
- return self.param.do_unmarshal(string)
+ return self.item_parameter.do_unmarshal(string)
def do_marshal(self, object):
- return self.param.do_marshal(object)
+ return self.item_parameter.do_marshal(object)
class IntegerParameter(Parameter):
def do_unmarshal(self, string):
17 years, 1 month
rhmessaging commits: r3176 - in mgmt/trunk: wooly/python/wooly and 1 other directory.
by rhmessaging-commits@lists.jboss.org
Author: justi9
Date: 2009-03-19 12:00:42 -0400 (Thu, 19 Mar 2009)
New Revision: 3176
Modified:
mgmt/trunk/cumin/python/cumin/broker.py
mgmt/trunk/cumin/python/cumin/brokergroup.py
mgmt/trunk/cumin/python/cumin/brokerlink.py
mgmt/trunk/cumin/python/cumin/client.py
mgmt/trunk/cumin/python/cumin/exchange.py
mgmt/trunk/cumin/python/cumin/job.py
mgmt/trunk/cumin/python/cumin/pool.py
mgmt/trunk/cumin/python/cumin/queue.py
mgmt/trunk/wooly/python/wooly/__init__.py
mgmt/trunk/wooly/python/wooly/pages.py
Log:
Rename the XXX_current_frame methods on WidgetPage to just XXX_frame
Modified: mgmt/trunk/cumin/python/cumin/broker.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/broker.py 2009-03-19 15:45:47 UTC (rev 3175)
+++ mgmt/trunk/cumin/python/cumin/broker.py 2009-03-19 16:00:42 UTC (rev 3176)
@@ -691,8 +691,8 @@
class BrokerSetAdd(BrokerSetForm):
def process_cancel(self, session):
branch = session.branch()
- self.page.pop_current_frame(branch)
- self.page.get_current_frame(branch).show_view(branch)
+ self.page.pop_frame(branch)
+ self.page.get_frame(branch).show_view(branch)
self.page.set_redirect_url(session, branch.marshal())
def process_submit(self, session):
@@ -787,8 +787,8 @@
def process_cancel(self, session, reg):
branch = session.branch()
- self.page.pop_current_frame(branch)
- self.page.get_current_frame(branch).show_view(branch)
+ self.page.pop_frame(branch)
+ self.page.get_frame(branch).show_view(branch)
self.page.set_redirect_url(session, branch.marshal())
def process_submit(self, session, reg):
Modified: mgmt/trunk/cumin/python/cumin/brokergroup.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/brokergroup.py 2009-03-19 15:45:47 UTC (rev 3175)
+++ mgmt/trunk/cumin/python/cumin/brokergroup.py 2009-03-19 16:00:42 UTC (rev 3176)
@@ -188,7 +188,7 @@
def process_cancel(self, session, group):
branch = session.branch()
self.frame.show_view(branch)
- self.page.pop_current_frame(branch)
+ self.page.pop_frame(branch)
self.page.set_redirect_url(session, branch.marshal())
def process_submit(self, session, group):
@@ -197,8 +197,8 @@
branch = session.branch()
self.frame.frame.show_view(branch)
- self.page.pop_current_frame(branch)
- self.page.pop_current_frame(branch)
+ self.page.pop_frame(branch)
+ self.page.pop_frame(branch)
self.page.set_redirect_url(session, branch.marshal())
def render_title(self, session, group):
Modified: mgmt/trunk/cumin/python/cumin/brokerlink.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/brokerlink.py 2009-03-19 15:45:47 UTC (rev 3175)
+++ mgmt/trunk/cumin/python/cumin/brokerlink.py 2009-03-19 16:00:42 UTC (rev 3176)
@@ -238,11 +238,11 @@
return super(PeerFrame, self).show_object(session, peer)
def show_bridge_add(self, session):
- self.page.set_current_frame(session, self.__bridge_add)
+ self.page.set_frame(session, self.__bridge_add)
return self.show_mode(session, self.__bridge_add)
def show_routes_close(self, session):
- self.page.set_current_frame(session, self.__routes_close)
+ self.page.set_frame(session, self.__routes_close)
return self.show_mode(session, self.__routes_close)
class LinkRemove(CuminConfirmForm):
@@ -663,7 +663,7 @@
def process_return(self, session):
branch = session.branch()
self.frame.show_view(branch)
- self.page.set_current_frame(branch, self.frame)
+ self.page.set_frame(branch, self.frame)
self.page.set_redirect_url(session, branch.marshal())
def process_item(self, session, id):
@@ -685,7 +685,7 @@
def process_return(self, session):
branch = session.branch()
self.frame.show_view(branch)
- self.page.set_current_frame(branch, self.frame)
+ self.page.set_frame(branch, self.frame)
self.page.set_redirect_url(session, branch.marshal())
def process_item(self, session, id):
Modified: mgmt/trunk/cumin/python/cumin/client.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/client.py 2009-03-19 15:45:47 UTC (rev 3175)
+++ mgmt/trunk/cumin/python/cumin/client.py 2009-03-19 16:00:42 UTC (rev 3176)
@@ -205,7 +205,7 @@
def process_return(self, session):
branch = session.branch()
self.frame.show_view(branch)
- self.page.set_current_frame(branch, self.frame)
+ self.page.set_frame(branch, self.frame)
self.page.set_redirect_url(session, branch.marshal())
def process_item(self, session, id):
@@ -283,7 +283,7 @@
def process_return(self, session):
branch = session.branch()
self.frame.show_view(branch).show_sessions(branch)
- self.page.set_current_frame(branch, self.frame)
+ self.page.set_frame(branch, self.frame)
self.page.set_redirect_url(session, branch.marshal())
def process_item(self, session, id):
@@ -301,7 +301,7 @@
def process_return(self, session):
branch = session.branch()
self.frame.show_view(branch).show_sessions(branch)
- self.page.set_current_frame(branch, self.frame)
+ self.page.set_frame(branch, self.frame)
self.page.set_redirect_url(session, branch.marshal())
def process_item(self, session, id):
@@ -368,7 +368,7 @@
branch = session.branch()
frame = self.frame.show_sessions_detach(branch)
frame.ids.set(branch, ids)
- self.page.set_current_frame(branch, frame)
+ self.page.set_frame(branch, frame)
self.page.set_redirect_url(session, branch.marshal())
class Close(FormButton):
@@ -382,7 +382,7 @@
branch = session.branch()
frame = self.frame.show_sessions_close(branch)
frame.ids.set(branch, ids)
- self.page.set_current_frame(branch, frame)
+ self.page.set_frame(branch, frame)
self.page.set_redirect_url(session, branch.marshal())
class NameColumn(SqlTableColumn):
Modified: mgmt/trunk/cumin/python/cumin/exchange.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/exchange.py 2009-03-19 15:45:47 UTC (rev 3175)
+++ mgmt/trunk/cumin/python/cumin/exchange.py 2009-03-19 16:00:42 UTC (rev 3176)
@@ -168,7 +168,7 @@
def process_return(self, session):
branch = session.branch()
self.frame.show_view(branch)
- self.page.set_current_frame(branch, self.frame)
+ self.page.set_frame(branch, self.frame)
self.page.set_redirect_url(session, branch.marshal())
def process_item(self, session, id):
Modified: mgmt/trunk/cumin/python/cumin/job.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/job.py 2009-03-19 15:45:47 UTC (rev 3175)
+++ mgmt/trunk/cumin/python/cumin/job.py 2009-03-19 16:00:42 UTC (rev 3176)
@@ -558,19 +558,19 @@
self.add_mode(self.__system)
def show_ads_edit(self, session):
- self.page.set_current_frame(session, self.__edit_ads)
+ self.page.set_frame(session, self.__edit_ads)
return self.show_mode(session, self.__edit_ads)
def show_job_group(self, session, jobgroup):
self.__job.set_object(session, jobgroup)
- self.page.set_current_frame(session, self.__job)
+ self.page.set_frame(session, self.__job)
self.__job.set_switch(session, "group")
return self.show_mode(session, self.__job)
def show_system(self, session, system):
frame = self.show_mode(session, self.__system)
frame.set_object(session, system)
- return self.page.set_current_frame(session, frame)
+ return self.page.set_frame(session, frame)
class JobView(CuminView):
@@ -800,8 +800,8 @@
def process_cancel(self, session, job):
branch = session.branch()
self.ads.set(branch, None) # otherwise url is too long
- self.page.pop_current_frame(branch)
- self.page.get_current_frame(branch).show_view(branch)
+ self.page.pop_frame(branch)
+ self.page.get_frame(branch).show_view(branch)
self.page.set_redirect_url(session, branch.marshal())
def process_submit(self, session, job):
@@ -1209,7 +1209,7 @@
def process_return(self, session, *args):
branch = session.branch()
self.frame.show_view(branch)
- self.page.set_current_frame(branch, self.frame)
+ self.page.set_frame(branch, self.frame)
self.page.set_redirect_url(session, branch.marshal())
def get_reason(self, session, verb):
Modified: mgmt/trunk/cumin/python/cumin/pool.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/pool.py 2009-03-19 15:45:47 UTC (rev 3175)
+++ mgmt/trunk/cumin/python/cumin/pool.py 2009-03-19 16:00:42 UTC (rev 3176)
@@ -136,31 +136,31 @@
self.add_mode(self.job_group_remove)
def show_job_frame(self, session):
- self.page.set_current_frame(session, self.job)
+ self.page.set_frame(session, self.job)
return self.show_mode(session, self.job)
def show_negs_start(self, session):
- self.page.set_current_frame(session, self.__startneg)
+ self.page.set_frame(session, self.__startneg)
return self.show_mode(session, self.__startneg)
def show_negs_stop(self, session):
- self.page.set_current_frame(session, self.__stopneg)
+ self.page.set_frame(session, self.__stopneg)
return self.show_mode(session, self.__stopneg)
def show_scheds_start(self, session):
- self.page.set_current_frame(session, self.__startsched)
+ self.page.set_frame(session, self.__startsched)
return self.show_mode(session, self.__startsched)
def show_scheds_stop(self, session):
- self.page.set_current_frame(session, self.__stopsched)
+ self.page.set_frame(session, self.__stopsched)
return self.show_mode(session, self.__stopsched)
def show_colls_start(self, session):
- self.page.set_current_frame(session, self.__startcoll)
+ self.page.set_frame(session, self.__startcoll)
return self.show_mode(session, self.__startcoll)
def show_colls_stop(self, session):
- self.page.set_current_frame(session, self.__stopcoll)
+ self.page.set_frame(session, self.__stopcoll)
return self.show_mode(session, self.__stopcoll)
class PoolView(CuminView):
Modified: mgmt/trunk/cumin/python/cumin/queue.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/queue.py 2009-03-19 15:45:47 UTC (rev 3175)
+++ mgmt/trunk/cumin/python/cumin/queue.py 2009-03-19 16:00:42 UTC (rev 3176)
@@ -648,7 +648,7 @@
def process_return(self, session):
branch = session.branch()
self.frame.show_view(branch)
- self.page.set_current_frame(branch, self.frame)
+ self.page.set_frame(branch, self.frame)
self.page.set_redirect_url(session, branch.marshal())
def process_item(self, session, id):
@@ -671,7 +671,7 @@
def process_return(self, session):
branch = session.branch()
self.frame.show_view(branch)
- self.page.set_current_frame(branch, self.frame)
+ self.page.set_frame(branch, self.frame)
self.page.set_redirect_url(session, branch.marshal())
def process_item(self, session, id):
Modified: mgmt/trunk/wooly/python/wooly/__init__.py
===================================================================
--- mgmt/trunk/wooly/python/wooly/__init__.py 2009-03-19 15:45:47 UTC (rev 3175)
+++ mgmt/trunk/wooly/python/wooly/__init__.py 2009-03-19 16:00:42 UTC (rev 3176)
@@ -294,10 +294,10 @@
def show(self, session):
super(Frame, self).show(session)
- return self.page.set_current_frame(session, self)
+ return self.page.set_frame(session, self)
def save_parameters(self, session, params):
- frame = self.page.get_current_frame(session)
+ frame = self.page.get_frame(session)
if self is frame or self in frame.ancestors:
super(Frame, self).save_parameters(session, params)
Modified: mgmt/trunk/wooly/python/wooly/pages.py
===================================================================
--- mgmt/trunk/wooly/python/wooly/pages.py 2009-03-19 15:45:47 UTC (rev 3175)
+++ mgmt/trunk/wooly/python/wooly/pages.py 2009-03-19 16:00:42 UTC (rev 3176)
@@ -12,8 +12,8 @@
self.widget_classes = set()
- self.__frame = self.FrameParameter(app, "frame")
- self.add_parameter(self.__frame)
+ self.page_frame = self.FrameParameter(app, "frame")
+ self.add_parameter(self.page_frame)
self.set_default_frame(self)
@@ -28,21 +28,20 @@
if cls is Widget:
break
- # XXX take "current" out of these
- def set_current_frame(self, session, frame):
- self.__frame.set(session, frame)
+ def set_frame(self, session, frame):
+ self.page_frame.set(session, frame)
return frame
- def get_current_frame(self, session):
- return self.__frame.get(session)
+ def get_frame(self, session):
+ return self.page_frame.get(session)
- def pop_current_frame(self, session):
- frame = self.get_current_frame(session)
+ def pop_frame(self, session):
+ frame = self.get_frame(session)
#print "Popping current frame", frame
- self.set_current_frame(session, frame.frame)
+ self.set_frame(session, frame.frame)
def set_default_frame(self, frame):
- self.__frame.default = frame
+ self.page_frame.default = frame
def get_page_parameters(self, session):
"""
@@ -55,7 +54,7 @@
of its ancestor frames.
"""
- frame = self.get_current_frame(session)
+ frame = self.get_frame(session)
try:
params = self.__saved_params[frame]
17 years, 1 month
rhmessaging commits: r3175 - mgmt/trunk/wooly/python/wooly.
by rhmessaging-commits@lists.jboss.org
Author: justi9
Date: 2009-03-19 11:45:47 -0400 (Thu, 19 Mar 2009)
New Revision: 3175
Modified:
mgmt/trunk/wooly/python/wooly/devel.py
mgmt/trunk/wooly/python/wooly/forms.py
mgmt/trunk/wooly/python/wooly/forms.strings
mgmt/trunk/wooly/python/wooly/model.py
mgmt/trunk/wooly/python/wooly/parameters.py
mgmt/trunk/wooly/python/wooly/resources.py
mgmt/trunk/wooly/python/wooly/tables.py
mgmt/trunk/wooly/python/wooly/widgets.py
mgmt/trunk/wooly/python/wooly/wsgiserver.py
Log:
Whitespace-only cleanup of wooly files
Modified: mgmt/trunk/wooly/python/wooly/devel.py
===================================================================
--- mgmt/trunk/wooly/python/wooly/devel.py 2009-03-19 15:12:52 UTC (rev 3174)
+++ mgmt/trunk/wooly/python/wooly/devel.py 2009-03-19 15:45:47 UTC (rev 3175)
@@ -16,7 +16,7 @@
visited = set()
self.app.debug.urls.add("")
count = 0
-
+
while True:
for url in self.app.debug.urls:
if url not in visited:
@@ -74,7 +74,7 @@
if count == max:
break
-
+
count += 1
class DevelPage(Page):
Modified: mgmt/trunk/wooly/python/wooly/forms.py
===================================================================
--- mgmt/trunk/wooly/python/wooly/forms.py 2009-03-19 15:12:52 UTC (rev 3174)
+++ mgmt/trunk/wooly/python/wooly/forms.py 2009-03-19 15:45:47 UTC (rev 3175)
@@ -27,9 +27,9 @@
origin = branch.marshal()
except: # we don't have a show_view
pass
-
+
return origin
-
+
def render_hidden_inputs(self, session, *args):
writer = Writer()
# remember our roots
@@ -41,7 +41,7 @@
for param in params:
key = param.path
-
+
if param.is_collection:
collection = session.get(key)
@@ -64,7 +64,7 @@
def write_hidden_input(self, name, value, writer):
writer.write("<input type='hidden' name='%s' value='%s'/>" \
% (name, value))
-
+
class FormError(object):
def __init__(self, message=None):
self.message = message
@@ -190,10 +190,10 @@
class HiddenInput(ScalarInput):
def __init__(self, app, name):
super(HiddenInput, self).__init__(app, name, None)
-
+
self.param = BooleanParameter(app, "param")
self.add_parameter(self.param)
-
+
class IntegerInput(ScalarInput):
def __init__(self, app, name):
super(IntegerInput, self).__init__(app, name, None)
@@ -251,13 +251,13 @@
self.set(branch, True)
return super(FormButton, self).render_value(branch, *args)
-
+
def render_type(self, session, *args):
return "submit"
def render_onclick(self, session, *args):
return "click_button"
-
+
class CheckboxInputSet(FormInput, ItemSet):
def render_item_value(self, session, *args):
return None
@@ -287,7 +287,7 @@
self.add_child(self.__errors)
self.css_class = "field"
-
+
def validate(self, session):
errors = self.__errors.get(session)
@@ -300,10 +300,10 @@
def render_field_help(self, session, *args):
pass
-
+
def render_form_field_class(self, session, *args):
return self.css_class
-
+
class ScalarField(FormField):
def __init__(self, app, name, input):
super(ScalarField, self).__init__(app, name)
@@ -338,7 +338,7 @@
self.input = PasswordInput(app, "input")
self.add_child(self.input)
-
+
class IntegerField(ScalarField):
def __init__(self, app, name):
super(IntegerField, self).__init__(app, name, None)
@@ -356,7 +356,7 @@
errors.append(error)
else:
self.set(session, self.input.param.get_default(session))
-
+
# XXX make this use a RadioInputSet instead?
class RadioField(FormField):
def __init__(self, app, name, param):
Modified: mgmt/trunk/wooly/python/wooly/forms.strings
===================================================================
--- mgmt/trunk/wooly/python/wooly/forms.strings 2009-03-19 15:12:52 UTC (rev 3174)
+++ mgmt/trunk/wooly/python/wooly/forms.strings 2009-03-19 15:45:47 UTC (rev 3175)
@@ -115,7 +115,7 @@
div.compact.last {
margin-bottom: 1em;
}
-
+
[FormField.html]
<div class="{form_field_class}">
<div class="title">{title}</div> <div class="field_help">{field_help}</div><div class="clear_left"></div>
Modified: mgmt/trunk/wooly/python/wooly/model.py
===================================================================
--- mgmt/trunk/wooly/python/wooly/model.py 2009-03-19 15:12:52 UTC (rev 3174)
+++ mgmt/trunk/wooly/python/wooly/model.py 2009-03-19 15:45:47 UTC (rev 3175)
@@ -40,7 +40,7 @@
if len(self.endpoints) > 1:
raise Exception("Too many endpoints")
-
+
endpoint = self.Endpoint()
endpoint.name = name
endpoint.multiplicity = multiplicity
@@ -144,7 +144,7 @@
new_that.unlock()
finally:
this.unlock()
-
+
class ModelObject(object):
sequence = 100
@@ -187,7 +187,7 @@
def do_add_method(self, that):
if that == None:
raise Exception()
-
+
end.add_object(this, that)
this.setmethod("do_add_" + end.name, do_add_method)
@@ -198,7 +198,7 @@
def do_remove_method(self, that):
if that == None:
raise Exception()
-
+
end.remove_object(this, that)
this.setmethod("do_remove_" + end.name, do_remove_method)
@@ -221,7 +221,7 @@
try:
for end in self.mclass.endpoints:
this = self
-
+
if end.is_scalar():
end.set_object(this, None)
else:
Modified: mgmt/trunk/wooly/python/wooly/parameters.py
===================================================================
--- mgmt/trunk/wooly/python/wooly/parameters.py 2009-03-19 15:12:52 UTC (rev 3174)
+++ mgmt/trunk/wooly/python/wooly/parameters.py 2009-03-19 15:45:47 UTC (rev 3175)
@@ -12,12 +12,12 @@
@classmethod
def sep(cls):
return "|"
-
+
def add(self, session, value, full_key):
# full_key looks like <DictParameter.path>_<stuff>
keys = self.get(session)
-
+
# separate the DictParameter.path from the stuff
foo, stuff = full_key.split(DictParameter.sep(), 1)
if stuff:
@@ -26,8 +26,8 @@
def split_stuff(self, keys, stuff, value):
""" Each time there is a delimiter in stuff,
create a nested dictionary entry """
-
- # can't use: stuff_1, stuff_2 = stuff.split(DictParameter.sep(), 1)
+
+ # can't use: stuff_1, stuff_2 = stuff.split(DictParameter.sep(), 1)
stuff_list = stuff.split(DictParameter.sep(), 1)
stuff_1 = stuff_list[0]
if len(stuff_list) > 1:
@@ -40,16 +40,16 @@
keys[stuff_1] = value
elif stuff_1 in keys:
del keys[stuff_1]
-
+
def get_instance_key(self, key):
return DictParameter.sep().join((self.path, key))
-
+
def get_default(self, session):
return copy(self.default)
def clear(self):
self.default = dict()
-
+
class ListParameter(Parameter):
def __init__(self, app, name, param):
super(ListParameter, self).__init__(app, name)
Modified: mgmt/trunk/wooly/python/wooly/resources.py
===================================================================
--- mgmt/trunk/wooly/python/wooly/resources.py 2009-03-19 15:12:52 UTC (rev 3174)
+++ mgmt/trunk/wooly/python/wooly/resources.py 2009-03-19 15:45:47 UTC (rev 3175)
@@ -19,7 +19,7 @@
def get(self, key):
if not self.strings:
self.load()
-
+
return self.strings.get(key)
def __repr__(self):
Modified: mgmt/trunk/wooly/python/wooly/tables.py
===================================================================
--- mgmt/trunk/wooly/python/wooly/tables.py 2009-03-19 15:12:52 UTC (rev 3174)
+++ mgmt/trunk/wooly/python/wooly/tables.py 2009-03-19 15:45:47 UTC (rev 3175)
@@ -23,7 +23,7 @@
def get_visible_columns(self, session):
# default impl
return [col for col in self.columns if col.visible]
-
+
def get_request_visible_columns(self, session, vlist):
return [col for col in self.columns if col.visible or col.name in vlist]
@@ -76,7 +76,7 @@
def set_default_column_name(self, name):
self.scolumn.default = name
-
+
def is_reversed(self, session):
return self.reversed.get(session)
@@ -131,7 +131,7 @@
# in case a non-sql column is included in an sqltable # XXX ugh
def get_orderby_sql(self, session):
pass
-
+
class ItemTableColumnHeader(Widget):
def __init__(self, app, name, column):
super(ItemTableColumnHeader, self).__init__(app, name)
@@ -170,7 +170,7 @@
return "unsorted_up"
else:
return "unsorted_down"
-
+
class SqlTable(ItemTable):
def __init__(self, app, name):
super(SqlTable, self).__init__(app, name)
@@ -210,7 +210,7 @@
def build_sql(self, elems):
writer = Writer()
-
+
for elem in elems:
if elem:
writer.write(elem)
@@ -272,26 +272,26 @@
def find_item(self, session, *args):
""" Find items in the current ItemSet
-
+
To use this an SqlTable derived object needs to have a
[<class>.find_sql] section and override render_find_sql_where
and get_find_sql_values.
Returns a list of dictionaries. Each dictionary is a matched row. """
-
+
conn = self.get_connection(session)
if conn:
cursor = conn.cursor()
select = self.render_find_sql(session, *args)
where = self.render_sql_where(session, *args)
sql_values = self.get_sql_values(session, *args)
-
+
find_where = self.render_find_sql_where(session, *args)
find_values = self.get_find_sql_values(session, *args)
sql = " and ".join(["%s %s" % (select, where), find_where])
if sql_values:
for sql_val in sql_values:
find_values[sql_val] = sql_values[sql_val]
-
+
try:
cursor.execute(sql, find_values)
return self.cursor_to_rows(cursor)
@@ -301,16 +301,16 @@
def cursor_to_rows(self, cursor):
cols = [spec[0] for spec in cursor.description]
rows = list()
-
+
for tuple in cursor:
row = dict()
for col, datum in zip(cols, tuple):
row[col] = datum
rows.append(row)
-
+
return rows
-
+
class SqlTableColumn(ItemTableColumn):
# XXX to be consistent with similar methods, rename to
# get_sql_order_by
Modified: mgmt/trunk/wooly/python/wooly/widgets.py
===================================================================
--- mgmt/trunk/wooly/python/wooly/widgets.py 2009-03-19 15:12:52 UTC (rev 3174)
+++ mgmt/trunk/wooly/python/wooly/widgets.py 2009-03-19 15:45:47 UTC (rev 3175)
@@ -204,7 +204,7 @@
def render_none(self, session, *args):
"""For producing a message when the set is empty"""
-
+
return None
class RenderingItemSet(Widget):
@@ -265,13 +265,13 @@
def get_items(self, session, *args):
"""Get the root items"""
pass
-
+
def get_child_items(self, session, *args):
pass
def render_child_items(self, session, *args):
writer = Writer()
-
+
for child in self.get_child_items(session, *args):
self.item_renderer.render(writer, session, child)
@@ -318,7 +318,7 @@
elif count < page_index * self.page_size:
self.pageset_index.set(session, 0)
self.page_index.set(session, 0)
-
+
return self.page_count.set(session, count)
def get_count(self, session):
@@ -335,10 +335,10 @@
def __link(self, href, content, class_=""):
return "<a href=\"%s\"%s>%s</a>" % \
(href, class_ and " class=\"%s\" " % class_ or " ", content)
-
+
def render_prev_page_link(self, session, *args):
page = self.page_index.get(session)
-
+
if page < 1:
html = self.__link(session.marshal(), "<", "pagenav disabled")
else:
@@ -415,7 +415,7 @@
def render_class_attr(self, session, page):
if self.widget.page_index.get(session) == page:
return " class=\"selected\""
-
+
def render_href(self, session, page):
branch = session.branch()
self.widget.page_index.set(branch, page)
@@ -462,13 +462,13 @@
class ActionRenderer(TemplateRenderer):
def render_href(self, session, action):
return action[2] and " href=\"%s\"" % action[0] or ""
-
+
def render_content(self, session, action):
return action[1]
-
+
def render_tag(self, session, action):
return action[2] and "a" or "span"
-
+
def escape_amp(string):
return str(string).replace("&", "&")
@@ -482,4 +482,4 @@
t += "&" + name + ";"
else:
t += i
- return t
+ return t
Modified: mgmt/trunk/wooly/python/wooly/wsgiserver.py
===================================================================
--- mgmt/trunk/wooly/python/wooly/wsgiserver.py 2009-03-19 15:12:52 UTC (rev 3174)
+++ mgmt/trunk/wooly/python/wooly/wsgiserver.py 2009-03-19 15:45:47 UTC (rev 3175)
@@ -1,27 +1,27 @@
# Copyright (c) 2004-2007, CherryPy Team (team(a)cherrypy.org)
# All rights reserved.
-# Redistribution and use in source and binary forms, with or without modification,
+# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
-# * Redistributions of source code must retain the above copyright notice,
+# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
-# * Neither the name of the CherryPy Team nor the names of its contributors
-# may be used to endorse or promote products derived from this software
+# * Neither the name of the CherryPy Team nor the names of its contributors
+# may be used to endorse or promote products derived from this software
# without specific prior written permission.
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
-# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""A high-speed, production ready, thread pooled, generic WSGI server.
@@ -30,23 +30,23 @@
(without using CherryPy's application machinery):
from cherrypy import wsgiserver
-
+
def my_crazy_app(environ, start_response):
status = '200 OK'
response_headers = [('Content-type','text/plain')]
start_response(status, response_headers)
return ['Hello world!\n']
-
- # Here we set our application to the script_name '/'
+
+ # Here we set our application to the script_name '/'
wsgi_apps = [('/', my_crazy_app)]
-
+
server = wsgiserver.CherryPyWSGIServer(('localhost', 8070), wsgi_apps,
server_name='localhost')
-
+
# Want SSL support? Just set these attributes
# server.ssl_certificate = <filename>
# server.ssl_private_key = <filename>
-
+
if __name__ == '__main__':
try:
server.start()
@@ -112,9 +112,9 @@
class HTTPRequest(object):
"""An HTTP Request (and response).
-
+
A single HTTP connection may consist of multiple request/response pairs.
-
+
connection: the HTTP Connection object which spawned this request.
rfile: the 'read' fileobject from the connection's socket
ready: when True, the request has been parsed and is ready to begin
@@ -128,13 +128,13 @@
transfer-coding. This value is set automatically inside
send_headers.
"""
-
+
def __init__(self, connection):
self.connection = connection
self.rfile = self.connection.rfile
self.sendall = self.connection.sendall
self.environ = connection.environ.copy()
-
+
self.ready = False
self.started_response = False
self.status = ""
@@ -142,7 +142,7 @@
self.sent_headers = False
self.close_connection = False
self.chunked_write = False
-
+
def parse_request(self):
"""Parse the next HTTP request start-line and message-headers."""
# HTTP/1.1 connections are persistent by default. If a client
@@ -157,7 +157,7 @@
# Force self.ready = False so the connection will close.
self.ready = False
return
-
+
if request_line == "\r\n":
# RFC 2616 sec 4.1: "...if the server is reading the protocol
# stream at the beginning of a message and receives a CRLF
@@ -167,27 +167,27 @@
if not request_line:
self.ready = False
return
-
+
server = self.connection.server
environ = self.environ
environ["SERVER_SOFTWARE"] = "%s WSGI Server" % server.version
-
+
method, path, req_protocol = request_line.strip().split(" ", 2)
environ["REQUEST_METHOD"] = method
-
+
# path may be an abs_path (including "http://host.domain.tld");
scheme, location, path, params, qs, frag = urlparse(path)
-
+
if frag:
self.simple_response("400 Bad Request",
"Illegal #fragment in Request-URI.")
return
-
+
if scheme:
environ["wsgi.url_scheme"] = scheme
if params:
path = path + ";" + params
-
+
# Unquote the path+params (e.g. "/this%20path" -> "this path").
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
#
@@ -196,7 +196,7 @@
# safely decoded." http://www.ietf.org/rfc/rfc2396.txt, sec 2.4.2
atoms = [unquote(x) for x in quoted_slash.split(path)]
path = "%2F".join(atoms)
-
+
if path == "*":
# This means, of course, that the last wsgi_app (shortest path)
# will always handle a URI of "*".
@@ -214,11 +214,11 @@
else:
self.simple_response("404 Not Found")
return
-
+
# Note that, like wsgiref and most other WSGI servers,
# we unquote the path but not the query string.
environ["QUERY_STRING"] = qs
-
+
# Compare request and server HTTP protocol versions, in case our
# server does not support the requested protocol. Limit our output
# to min(req, server). We want the following output:
@@ -243,24 +243,24 @@
# See http://www.faqs.org/rfcs/rfc2145.html.
environ["ACTUAL_SERVER_PROTOCOL"] = server.protocol
self.response_protocol = "HTTP/%s.%s" % min(rp, sp)
-
+
# If the Request-URI was an absoluteURI, use its location atom.
if location:
environ["SERVER_NAME"] = location
-
+
# then all the http headers
try:
self.read_headers()
except ValueError, ex:
self.simple_response("400 Bad Request", repr(ex.args))
return
-
+
creds = environ.get("HTTP_AUTHORIZATION", "").split(" ", 1)
environ["AUTH_TYPE"] = creds[0]
if creds[0].lower() == 'basic':
user, pw = base64.decodestring(creds[1]).split(":", 1)
environ["REMOTE_USER"] = user
-
+
# Persistent connection support
if self.response_protocol == "HTTP/1.1":
if environ.get("HTTP_CONNECTION", "") == "close":
@@ -269,16 +269,16 @@
# HTTP/1.0
if environ.get("HTTP_CONNECTION", "") != "Keep-Alive":
self.close_connection = True
-
+
# Transfer-Encoding support
te = None
if self.response_protocol == "HTTP/1.1":
te = environ.get("HTTP_TRANSFER_ENCODING")
if te:
te = [x.strip().lower() for x in te.split(",") if x.strip()]
-
+
read_chunked = False
-
+
if te:
for enc in te:
if enc == "chunked":
@@ -289,11 +289,11 @@
self.simple_response("501 Unimplemented")
self.close_connection = True
return
-
+
if read_chunked:
if not self.decode_chunked():
return
-
+
# From PEP 333:
# "Servers and gateways that implement HTTP 1.1 must provide
# transparent support for HTTP 1.1's "expect/continue" mechanism.
@@ -313,23 +313,23 @@
# but it seems like it would be a big slowdown for such a rare case.
if environ.get("HTTP_EXPECT", "") == "100-continue":
self.simple_response(100)
-
+
self.ready = True
-
+
def read_headers(self):
"""Read header lines from the incoming stream."""
environ = self.environ
-
+
while True:
line = self.rfile.readline()
if not line:
# No more data--illegal end of headers
raise ValueError("Illegal end of headers.")
-
+
if line == '\r\n':
# Normal end of headers
break
-
+
if line[0] in ' \t':
# It's a continuation line.
v = line.strip()
@@ -337,20 +337,20 @@
k, v = line.split(":", 1)
k, v = k.strip().upper(), v.strip()
envname = "HTTP_" + k.replace("-", "_")
-
+
if k in comma_separated_headers:
existing = environ.get(envname)
if existing:
v = ", ".join((existing, v))
environ[envname] = v
-
+
ct = environ.pop("HTTP_CONTENT_TYPE", None)
if ct:
environ["CONTENT_TYPE"] = ct
cl = environ.pop("HTTP_CONTENT_LENGTH", None)
if cl:
environ["CONTENT_LENGTH"] = cl
-
+
def decode_chunked(self):
"""Decode the 'chunked' transfer coding."""
cl = 0
@@ -369,15 +369,15 @@
"Bad chunked transfer coding "
"(expected '\\r\\n', got %r)" % crlf)
return
-
+
# Grab any trailer headers
self.read_headers()
-
+
data.seek(0)
self.environ["wsgi.input"] = data
self.environ["CONTENT_LENGTH"] = str(cl) or ""
return True
-
+
def respond(self):
"""Call the appropriate WSGI app and write its iterable output."""
response = self.wsgi_app(self.environ, self.start_response)
@@ -400,23 +400,23 @@
self.send_headers()
if self.chunked_write:
self.sendall("0\r\n\r\n")
-
+
def simple_response(self, status, msg=""):
"""Write a simple response back to the client."""
status = str(status)
buf = ["%s %s\r\n" % (self.connection.server.protocol, status),
"Content-Length: %s\r\n" % len(msg)]
-
+
if status[:3] == "413" and self.response_protocol == 'HTTP/1.1':
# Request Entity Too Large
self.close_connection = True
buf.append("Connection: close\r\n")
-
+
buf.append("\r\n")
if msg:
buf.append(msg)
self.sendall("".join(buf))
-
+
def start_response(self, status, headers, exc_info = None):
"""WSGI callable to begin the HTTP response."""
if self.started_response:
@@ -432,31 +432,31 @@
self.status = status
self.outheaders.extend(headers)
return self.write
-
+
def write(self, chunk):
"""WSGI callable to write unbuffered data to the client.
-
+
This method is also used internally by start_response (to write
data from the iterable returned by the WSGI application).
"""
if not self.started_response:
raise AssertionError("WSGI write called before start_response.")
-
+
if not self.sent_headers:
self.sent_headers = True
self.send_headers()
-
+
if self.chunked_write and chunk:
buf = [hex(len(chunk))[2:], "\r\n", chunk, "\r\n"]
self.sendall("".join(buf))
else:
self.sendall(chunk)
-
+
def send_headers(self):
"""Assert, process, and send the HTTP response message-headers."""
hkeys = [key.lower() for key, value in self.outheaders]
status = int(self.status[:3])
-
+
if status == 413:
# Request Entity Too Large. Close conn to avoid garbage.
self.close_connection = True
@@ -474,7 +474,7 @@
else:
# Closing the conn is the only way to determine len.
self.close_connection = True
-
+
if "connection" not in hkeys:
if self.response_protocol == 'HTTP/1.1':
if self.close_connection:
@@ -482,15 +482,15 @@
else:
if not self.close_connection:
self.outheaders.append(("Connection", "Keep-Alive"))
-
+
if "date" not in hkeys:
self.outheaders.append(("Date", rfc822.formatdate()))
-
+
server = self.connection.server
-
+
if "server" not in hkeys:
self.outheaders.append(("Server", server.version))
-
+
buf = [server.protocol, " ", self.status, "\r\n"]
try:
buf += [k + ": " + v + "\r\n" for k, v in self.outheaders]
@@ -512,7 +512,7 @@
def _ssl_wrap_method(method, is_reader=False):
"""Wrap the given method with SSL error-trapping.
-
+
is_reader: if False (the default), EOF errors will be raised.
If True, EOF errors will return "" (to emulate normal sockets).
"""
@@ -531,7 +531,7 @@
except SSL.SysCallError, e:
if is_reader and e.args == (-1, 'Unexpected EOF'):
return ""
-
+
errno = e.args[0]
if is_reader and errno in socket_errors_to_ignore:
return ""
@@ -539,13 +539,13 @@
except SSL.Error, e:
if is_reader and e.args == (-1, 'Unexpected EOF'):
return ""
-
+
thirdarg = None
try:
thirdarg = e.args[0][0][2]
except IndexError:
pass
-
+
if is_reader and thirdarg == 'ssl handshake failure':
return ""
if thirdarg == 'http request':
@@ -558,10 +558,10 @@
class SSL_fileobject(socket._fileobject):
"""Faux file object attached to a socket object."""
-
+
ssl_timeout = 3
ssl_retry = .01
-
+
close = _ssl_wrap_method(socket._fileobject.close)
flush = _ssl_wrap_method(socket._fileobject.flush)
write = _ssl_wrap_method(socket._fileobject.write)
@@ -573,7 +573,7 @@
class HTTPConnection(object):
"""An HTTP connection (active socket).
-
+
socket: the raw socket object (usually TCP) for this connection.
addr: the "bind address" for the remote end of the socket.
For IP sockets, this is a tuple of (REMOTE_ADDR, REMOTE_PORT).
@@ -581,12 +581,12 @@
server: the HTTP Server for this Connection. Usually, the server
object possesses a passive (server) socket which spawns multiple,
active (client) sockets, one for each connection.
-
+
environ: a WSGI environ template. This will be copied for each request.
rfile: a fileobject for reading from the socket.
sendall: a function for writing (+ flush) to the socket.
"""
-
+
rbufsize = -1
RequestHandlerClass = HTTPRequest
environ = {"wsgi.version": (1, 0),
@@ -596,16 +596,16 @@
"wsgi.run_once": False,
"wsgi.errors": sys.stderr,
}
-
+
def __init__(self, sock, addr, server):
self.socket = sock
self.addr = addr
self.server = server
self.__aborted = False
-
+
# Copy the class environ into self.
self.environ = self.environ.copy()
-
+
if SSL and isinstance(sock, SSL.ConnectionType):
timeout = sock.gettimeout()
self.rfile = SSL_fileobject(sock, "r", self.rbufsize)
@@ -619,11 +619,11 @@
else:
self.rfile = sock.makefile("rb", self.rbufsize)
self.sendall = sock.sendall
-
+
self.environ.update({"wsgi.input": self.rfile,
"SERVER_NAME": self.server.server_name,
})
-
+
if isinstance(self.server.bind_addr, basestring):
# AF_UNIX. This isn't really allowed by WSGI, which doesn't
# address unix domain sockets. But it's better than nothing.
@@ -637,7 +637,7 @@
def abort(self):
self.__aborted = True
-
+
def communicate(self):
"""Read each request and respond appropriately."""
try:
@@ -676,7 +676,7 @@
except:
if req:
req.simple_response("500 Internal Server Error", format_exc())
-
+
def close(self):
"""Close the socket underlying this connection."""
self.rfile.close()
@@ -696,24 +696,24 @@
class WorkerThread(threading.Thread):
"""Thread which continuously polls a Queue for Connection objects.
-
+
server: the HTTP Server which spawned this thread, and which owns the
Queue and is placing active connections into it.
ready: a simple flag for the calling server to know when this thread
has begun polling the Queue.
-
+
Due to the timing issues of polling a Queue, a WorkerThread does not
check its own 'ready' flag after it has started. To stop the thread,
it is necessary to stick a _SHUTDOWNREQUEST object onto the Queue
(one for each running WorkerThread).
"""
-
+
def __init__(self, server):
self.ready = False
self.server = server
self.currentConnection = None
threading.Thread.__init__(self)
-
+
def run(self):
try:
self.ready = True
@@ -721,7 +721,7 @@
conn = self.server.requests.get()
if conn is _SHUTDOWNREQUEST:
return
-
+
self.currentConnection = conn
try:
@@ -734,14 +734,14 @@
class SSLConnection:
"""A thread-safe wrapper for an SSL.Connection.
-
+
*args: the arguments to create the wrapped SSL.Connection(*args).
"""
-
+
def __init__(self, *args):
self._ssl_conn = SSL.Connection(*args)
self._lock = threading.RLock()
-
+
for f in ('get_context', 'pending', 'send', 'write', 'recv', 'read',
'renegotiate', 'bind', 'listen', 'connect', 'accept',
'setblocking', 'fileno', 'shutdown', 'close', 'get_cipher_list',
@@ -761,7 +761,7 @@
class CherryPyWSGIServer(object):
"""An HTTP server for WSGI.
-
+
bind_addr: a (host, port) tuple if TCP sockets are desired;
for UNIX sockets, supply the filename as a string.
wsgi_app: the WSGI 'application callable'; multiple WSGI applications
@@ -773,39 +773,39 @@
request_queue_size: the 'backlog' argument to socket.listen();
specifies the maximum number of queued connections (default 5).
timeout: the timeout in seconds for accepted connections (default 10).
-
+
protocol: the version string to write in the Status-Line of all
HTTP responses. For example, "HTTP/1.1" (the default). This
also limits the supported features used in the response.
-
-
+
+
SSL/HTTPS
---------
The OpenSSL module must be importable for SSL functionality.
You can obtain it from http://pyopenssl.sourceforge.net/
-
+
ssl_certificate: the filename of the server SSL certificate.
ssl_privatekey: the filename of the server's private key file.
-
+
If either of these is None (both are None by default), this server
will not use SSL. If both are given and are valid, they will be read
on server start and used in the SSL context for the listening socket.
"""
-
+
protocol = "HTTP/1.1"
version = "CherryPy/3.0.3"
ready = False
_interrupt = None
ConnectionClass = HTTPConnection
-
+
# Paths to certificate and private key files
ssl_certificate = None
ssl_private_key = None
-
+
def __init__(self, bind_addr, wsgi_app, numthreads=10, server_name=None,
max=-1, request_queue_size=5, timeout=10):
self.requests = Queue.Queue(max)
-
+
if callable(wsgi_app):
# We've been handed a single wsgi_app, in CP-2.1 style.
# Assume it's mounted at "".
@@ -817,7 +817,7 @@
self.mount_points = wsgi_app
self.mount_points.sort()
self.mount_points.reverse()
-
+
self.bind_addr = bind_addr
self.numthreads = numthreads or 1
if not server_name:
@@ -825,9 +825,9 @@
self.server_name = server_name
self.request_queue_size = request_queue_size
self._workerThreads = []
-
+
self.timeout = timeout
-
+
def start(self):
"""Run the server forever."""
# We don't have to trap KeyboardInterrupt or SystemExit here,
@@ -835,19 +835,19 @@
# If you're using this server with another framework, you should
# trap those exceptions in whatever code block calls start().
self._interrupt = None
-
+
# Select the appropriate socket
if isinstance(self.bind_addr, basestring):
# AF_UNIX socket
-
+
# So we can reuse the socket...
try: os.unlink(self.bind_addr)
except: pass
-
+
# So everyone can access the socket...
try: os.chmod(self.bind_addr, 0777)
except: pass
-
+
info = [(socket.AF_UNIX, socket.SOCK_STREAM, 0, "", self.bind_addr)]
else:
# AF_INET or AF_INET6 socket
@@ -871,7 +871,7 @@
except socket.gaierror:
# Probably a DNS issue. Assume IPv4.
info = [(socket.AF_INET, socket.SOCK_STREAM, 0, "", self.bind_addr)]
-
+
self.socket = None
msg = "No socket could be created"
for res in info:
@@ -886,11 +886,11 @@
break
if not self.socket:
raise socket.error, msg
-
+
# Timeout so KeyboardInterrupt can be caught on Win32
self.socket.settimeout(1)
self.socket.listen(self.request_queue_size)
-
+
# Create worker threads
for i in xrange(self.numthreads):
self._workerThreads.append(WorkerThread(self))
@@ -900,7 +900,7 @@
for worker in self._workerThreads:
while not worker.ready:
time.sleep(.1)
-
+
self.ready = True
while self.ready:
self.tick()
@@ -909,7 +909,7 @@
# Wait for self.stop() to complete. See _set_interrupt.
time.sleep(0.1)
raise self.interrupt
-
+
def bind(self, family, type, proto=0):
"""Create (or recreate) the actual socket object."""
self.socket = socket.socket(family, type, proto)
@@ -918,7 +918,7 @@
if self.ssl_certificate and self.ssl_private_key:
if SSL is None:
raise ImportError("You must install pyOpenSSL to use HTTPS.")
-
+
# See http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/442473
ctx = SSL.Context(SSL.SSLv23_METHOD)
ctx.use_privatekey_file(self.ssl_private_key)
@@ -926,7 +926,7 @@
self.socket = SSLConnection(ctx, self.socket)
self.populate_ssl_environ()
self.socket.bind(self.bind_addr)
-
+
def tick(self):
"""Accept a new connection and put it on the Queue."""
try:
@@ -951,7 +951,7 @@
# Just try again. See http://www.cherrypy.org/ticket/479.
return
raise
-
+
def _get_interrupt(self):
return self._interrupt
def _set_interrupt(self, interrupt):
@@ -961,11 +961,11 @@
interrupt = property(_get_interrupt, _set_interrupt,
doc="Set this to an Exception instance to "
"interrupt the server.")
-
+
def stop(self):
"""Gracefully shutdown a server that is serving forever."""
self.ready = False
-
+
sock = getattr(self, "socket", None)
if sock:
if not isinstance(self.bind_addr, basestring):
@@ -997,12 +997,12 @@
if hasattr(sock, "close"):
sock.close()
self.socket = None
-
+
# Must shut down threads here so the code that calls
# this method can know when all threads are stopped.
for worker in self._workerThreads:
self.requests.put(_SHUTDOWNREQUEST)
-
+
# Don't join currentThread (when stop is called inside a request).
current = threading.currentThread()
while self._workerThreads:
@@ -1014,7 +1014,7 @@
worker.join()
except AssertionError:
pass
-
+
def populate_ssl_environ(self):
"""Create WSGI environ entries to be merged into each request."""
cert = open(self.ssl_certificate).read()
@@ -1022,11 +1022,11 @@
self.ssl_environ = {
# pyOpenSSL doesn't provide access to any of these AFAICT
## 'SSL_PROTOCOL': 'SSLv2',
-## SSL_CIPHER string The cipher specification name
-## SSL_VERSION_INTERFACE string The mod_ssl program version
-## SSL_VERSION_LIBRARY string The OpenSSL program version
+## SSL_CIPHER string The cipher specification name
+## SSL_VERSION_INTERFACE string The mod_ssl program version
+## SSL_VERSION_LIBRARY string The OpenSSL program version
}
-
+
# Server certificate attributes
self.ssl_environ.update({
'SSL_SERVER_M_VERSION': cert.get_version(),
@@ -1034,17 +1034,17 @@
## 'SSL_SERVER_V_START': Validity of server's certificate (start time),
## 'SSL_SERVER_V_END': Validity of server's certificate (end time),
})
-
+
for prefix, dn in [("I", cert.get_issuer()),
("S", cert.get_subject())]:
# X509Name objects don't seem to have a way to get the
# complete DN string. Use str() and slice it instead,
# because str(dn) == "<X509Name object '/C=US/ST=...'>"
dnstr = str(dn)[18:-2]
-
+
wsgikey = 'SSL_SERVER_%s_DN' % prefix
self.ssl_environ[wsgikey] = dnstr
-
+
# The DN should be of the form: /k1=v1/k2=v2, but we must allow
# for any value to contain slashes itself (in a URL).
while dnstr:
@@ -1055,5 +1055,3 @@
if key and value:
wsgikey = 'SSL_SERVER_%s_DN_%s' % (prefix, key)
self.ssl_environ[wsgikey] = value
-
-
17 years, 1 month
rhmessaging commits: r3174 - in mgmt/trunk: cumin/python/cumin and 1 other directories.
by rhmessaging-commits@lists.jboss.org
Author: justi9
Date: 2009-03-19 11:12:52 -0400 (Thu, 19 Mar 2009)
New Revision: 3174
Modified:
mgmt/trunk/basil/python/basil/server.py
mgmt/trunk/cumin/python/cumin/__init__.py
mgmt/trunk/wooly/python/wooly/__init__.py
mgmt/trunk/wooly/python/wooly/server.py
Log:
Make resource page a default feature of Application
Modified: mgmt/trunk/basil/python/basil/server.py
===================================================================
--- mgmt/trunk/basil/python/basil/server.py 2009-03-19 14:17:09 UTC (rev 3173)
+++ mgmt/trunk/basil/python/basil/server.py 2009-03-19 15:12:52 UTC (rev 3174)
@@ -24,9 +24,6 @@
self.add_resource_dir("/home/jross/checkouts/mgmt/trunk/cumin-test-0/resources-wooly") # XXX
- page = ResourcePage(self, "resource")
- self.add_page(page)
-
self.enable_debug()
def init(self):
Modified: mgmt/trunk/cumin/python/cumin/__init__.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/__init__.py 2009-03-19 14:17:09 UTC (rev 3173)
+++ mgmt/trunk/cumin/python/cumin/__init__.py 2009-03-19 15:12:52 UTC (rev 3174)
@@ -35,6 +35,7 @@
self.enable_debug()
self.home = self.config.home
+
self.add_resource_dir(os.path.join(self.home, "resources-wooly"))
self.add_resource_dir(os.path.join(self.home, "resources"))
@@ -55,15 +56,12 @@
unprotected.add(self.main_page.css_page)
unprotected.add(self.main_page.javascript_page)
+ unprotected.add(self.resource_page)
self.login_page = LoginPage(self, "login")
self.add_page(self.login_page)
unprotected.add(self.login_page)
- page = ResourcePage(self, "resource")
- self.add_page(page)
- unprotected.add(page)
-
self.unprotected_pages = unprotected
self.user_sessions_by_id = dict()
Modified: mgmt/trunk/wooly/python/wooly/__init__.py
===================================================================
--- mgmt/trunk/wooly/python/wooly/__init__.py 2009-03-19 14:17:09 UTC (rev 3173)
+++ mgmt/trunk/wooly/python/wooly/__init__.py 2009-03-19 15:12:52 UTC (rev 3174)
@@ -410,9 +410,12 @@
class Application(object):
def __init__(self):
- self.pages = dict()
- self.default_page = None
+ self.pages = list()
+ self.pages_by_name = dict()
+ self.resource_page = ResourcePage(self, "resource")
+ self.add_page(self.resource_page)
+
self.finder = ResourceFinder()
self.debug = None
@@ -430,17 +433,18 @@
if page.parent:
raise Exception("Page '%s' is not a root widget" % page.name)
- if page.name in self.pages:
+ if page.name in self.pages_by_name:
raise Exception \
("A page called '%s' has already been added" % page.name)
- self.pages[page.name] = page
+ self.pages.append(page)
+ self.pages_by_name[page.name] = page
# XXX I don't think this should be triggered here
page.init()
def set_default_page(self, page):
- self.pages[""] = page
+ self.pages_by_name[""] = page
def add_resource_dir(self, dir):
self.finder.add_dir(dir)
@@ -449,7 +453,7 @@
return self.finder.find(name)
def __repr__(self):
- return "%s(default_page=%s)" % (self.__class__.__name__, self.default_page)
+ return self.__class__.__name__
class Session(object):
http_date_gmt = "%a, %d %b %Y %H:%M:%S GMT"
@@ -597,7 +601,7 @@
if name.startswith("/"):
name = name[1:]
- page = app.pages[name]
+ page = app.pages_by_name[name]
except KeyError:
raise Exception("Page '%s' not found" % name)
@@ -863,3 +867,5 @@
for call in self.callees:
call.write(writer)
+
+from pages import ResourcePage
Modified: mgmt/trunk/wooly/python/wooly/server.py
===================================================================
--- mgmt/trunk/wooly/python/wooly/server.py 2009-03-19 14:17:09 UTC (rev 3173)
+++ mgmt/trunk/wooly/python/wooly/server.py 2009-03-19 15:12:52 UTC (rev 3174)
@@ -41,7 +41,7 @@
name = env["PATH_INFO"][1:]
try:
- page = self.app.pages[name]
+ page = self.app.pages_by_name[name]
except KeyError:
return self.not_found(respond, headers)
@@ -50,7 +50,7 @@
if "HTTP_USER_AGENT" in env:
page.set_agent(session, env["HTTP_USER_AGENT"])
-
+
if env["REQUEST_METHOD"] == "POST":
if env["CONTENT_TYPE"] == "application/x-www-form-urlencoded":
length = int(env["CONTENT_LENGTH"])
@@ -78,7 +78,7 @@
return self.redirect(respond, headers, url)
else:
return self.unauthorized(respond, headers)
-
+
try:
page.process(session)
except:
17 years, 1 month
rhmessaging commits: r3173 - mgmt/trunk/wooly/python/wooly.
by rhmessaging-commits@lists.jboss.org
Author: justi9
Date: 2009-03-19 10:17:09 -0400 (Thu, 19 Mar 2009)
New Revision: 3173
Modified:
mgmt/trunk/wooly/python/wooly/__init__.py
Log:
Add missing init_widget for Page, so we make sure we pick up css and javascript resources for page widgets
Modified: mgmt/trunk/wooly/python/wooly/__init__.py
===================================================================
--- mgmt/trunk/wooly/python/wooly/__init__.py 2009-03-18 21:26:34 UTC (rev 3172)
+++ mgmt/trunk/wooly/python/wooly/__init__.py 2009-03-19 14:17:09 UTC (rev 3173)
@@ -334,6 +334,7 @@
self.page = self
self.frame = self
+ self.init_widget(self)
self.init_children()
self.sealed = True
17 years, 1 month
rhmessaging commits: r3172 - mgmt/trunk/cumin/python/cumin.
by rhmessaging-commits@lists.jboss.org
Author: justi9
Date: 2009-03-18 17:26:34 -0400 (Wed, 18 Mar 2009)
New Revision: 3172
Modified:
mgmt/trunk/cumin/python/cumin/__init__.py
mgmt/trunk/cumin/python/cumin/user.py
mgmt/trunk/cumin/python/cumin/user.strings
Log:
Change the login page to use HtmlPage
Modified: mgmt/trunk/cumin/python/cumin/__init__.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/__init__.py 2009-03-18 21:17:16 UTC (rev 3171)
+++ mgmt/trunk/cumin/python/cumin/__init__.py 2009-03-18 21:26:34 UTC (rev 3172)
@@ -56,7 +56,7 @@
unprotected.add(self.main_page.css_page)
unprotected.add(self.main_page.javascript_page)
- self.login_page = LoginPage(self, "login.html")
+ self.login_page = LoginPage(self, "login")
self.add_page(self.login_page)
unprotected.add(self.login_page)
Modified: mgmt/trunk/cumin/python/cumin/user.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/user.py 2009-03-18 21:17:16 UTC (rev 3171)
+++ mgmt/trunk/cumin/python/cumin/user.py 2009-03-18 21:26:34 UTC (rev 3172)
@@ -52,10 +52,12 @@
log.debug("Expired %i user sessions", count)
-class LoginPage(Page):
+class LoginPage(HtmlPage):
def __init__(self, app, name):
super(LoginPage, self).__init__(app, name)
+ self.html_class = LoginPage.__name__
+
self.logout = BooleanParameter(app, "logout")
self.add_parameter(self.logout)
Modified: mgmt/trunk/cumin/python/cumin/user.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/user.strings 2009-03-18 21:17:16 UTC (rev 3171)
+++ mgmt/trunk/cumin/python/cumin/user.strings 2009-03-18 21:26:34 UTC (rev 3172)
@@ -4,22 +4,6 @@
padding: 4em;
}
-[LoginPage.html]
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
- <head>
- <title>{title}</title>
- <link rel="stylesheet" type="text/css" href="cumin.css"/>
- <link rel="shortcut icon" href="resource?name=favicon.ico" type="image/x-icon"/>
- <script src="resource?name=wooly.js" type="text/javascript"> </script>
- <script src="cumin.js" type="text/javascript"> </script>
- </head>
- <body class="LoginPage">
- {form}
- </body>
-</html>
-
[LoginForm.css]
form.LoginForm {
background: #fff;
17 years, 1 month
rhmessaging commits: r3171 - mgmt/trunk/wooly/python/wooly.
by rhmessaging-commits@lists.jboss.org
Author: justi9
Date: 2009-03-18 17:17:16 -0400 (Wed, 18 Mar 2009)
New Revision: 3171
Modified:
mgmt/trunk/wooly/python/wooly/__init__.py
mgmt/trunk/wooly/python/wooly/forms.py
mgmt/trunk/wooly/python/wooly/pages.py
Log:
Make Page rather than Application responsible for keeping global
widget and parameter state.
Introduce WidgetPage, to encapsulate frame-based state preservation.
This way we don't have things like CssPage thinking about that.
Add methods on Page to pass control during widget and parameter
initialization back to the page.
Modified: mgmt/trunk/wooly/python/wooly/__init__.py
===================================================================
--- mgmt/trunk/wooly/python/wooly/__init__.py 2009-03-18 18:45:18 UTC (rev 3170)
+++ mgmt/trunk/wooly/python/wooly/__init__.py 2009-03-18 21:17:16 UTC (rev 3171)
@@ -22,7 +22,9 @@
self.path = None
def init(self):
- if self.widget.path:
+ #print "Initializing %s" % str(self)
+
+ if self.widget and self.widget.path:
self.path = ".".join((self.widget.path, self.name))
else:
self.path = self.name
@@ -64,8 +66,11 @@
self.is_collection = False
self.is_dictionary = False
- app.add_parameter(self)
+ def init(self):
+ super(Parameter, self).init()
+ self.widget.page.init_parameter(self)
+
def marshal(self, object):
if object == None:
string = ""
@@ -107,14 +112,6 @@
self.__main_tmpl = Template(self, "html")
- app.add_widget(self)
-
- # XXX eliminate this
- for cls in self.__class__.__mro__:
- app.add_widget_class(cls)
- if cls is Widget:
- break
-
def init(self):
#print "Initializing %s" % str(self)
@@ -138,11 +135,12 @@
pelems.append(self.name)
self.path = ".".join(pelems[1:])
- assert isinstance(self.ancestors[-1], Page)
self.page = self.ancestors[-1]
- self.page.widgets_by_path[self.path] = self
+ assert isinstance(self.page, Page)
+ self.page.init_widget(self)
+
self.sealed = True
self.init_children()
@@ -315,17 +313,15 @@
def __init__(self, app, name):
super(Page, self).__init__(app, name)
+ self.page_widgets = list()
+ self.page_widgets_by_path = dict()
+
+ self.page_parameters = list()
+ self.page_parameters_by_path = dict()
+
self.redirect = Attribute(app, "redirect")
self.add_attribute(self.redirect)
- self.current_frame = self.FrameParameter(app, "frame")
- self.add_parameter(self.current_frame)
- self.set_default_frame(self)
-
- self.widgets_by_path = dict()
-
- self.__saved_params = dict()
-
self.agent = Attribute(app, "agent")
self.add_attribute(self.agent)
@@ -338,13 +334,38 @@
self.page = self
self.frame = self
+ self.init_children()
+
self.sealed = True
- self.init_children()
+ def init_widget(self, widget):
+ assert not self.sealed
+ assert isinstance(widget, Widget)
- def render_id(self, session, *args):
- return self.name
+ self.page_widgets.append(widget)
+ self.page_widgets_by_path[widget.path] = widget
+ def init_parameter(self, param):
+ assert not self.sealed
+ assert isinstance(param, Parameter)
+
+ self.page_parameters.append(param)
+ self.page_parameters_by_path[param.path] = param
+
+ def get_page_parameter_by_path(self, path):
+ param = self.page_parameters_by_path.get(path)
+
+ # check for partial match for dictparameters
+ if not param:
+ if DictParameter.sep() in path:
+ dict_key = key.split(DictParameter.sep(), 1)[0]
+ param = self.page_parameters_by_path.get(dict_key)
+
+ return param
+
+ def get_page_parameters(self, session):
+ return self.page_parameters
+
def get_last_modified(self, session):
return datetime.utcnow()
@@ -378,54 +399,12 @@
def get_redirect_url(self, session):
return self.redirect.get(session)
- # XXX take "current" out of these
- def set_current_frame(self, session, frame):
- self.current_frame.set(session, frame)
- return frame
-
- def get_current_frame(self, session):
- return self.current_frame.get(session)
-
- def pop_current_frame(self, session):
- frame = self.get_current_frame(session)
- #print "Popping current frame", frame
- self.set_current_frame(session, frame.frame)
-
def set_agent(self, session, agent):
self.agent.set(session, agent)
- def set_default_frame(self, frame):
- self.current_frame.default = frame
+ def render_id(self, session, *args):
+ return self.name
- def get_saved_parameters(self, session):
- """
- Gets a list of parameters saved for this page and its current
- frame.
-
- This, combined with [gs]et_current_frame, serves to discard
- state that is out of scope. The current pattern is to
- preserve the state of parameters in the current frame and all
- of its ancestor frames.
- """
-
- frame = self.get_current_frame(session)
-
- try:
- params = self.__saved_params[frame]
- except KeyError:
- params = list()
- self.save_parameters(session, params)
- self.__saved_params[frame] = params
-
- return params
-
- class FrameParameter(Parameter):
- def do_marshal(self, frame):
- return frame.path
-
- def do_unmarshal(self, path):
- return self.app.get_widget(path)
-
from parameters import DictParameter
class Application(object):
@@ -433,14 +412,6 @@
self.pages = dict()
self.default_page = None
- self.widgets = list()
- self.widget_index = None
-
- self.widget_classes = set()
-
- self.parameters = list()
- self.parameter_index = None
-
self.finder = ResourceFinder()
self.debug = None
@@ -464,57 +435,12 @@
self.pages[page.name] = page
+ # XXX I don't think this should be triggered here
page.init()
def set_default_page(self, page):
self.pages[""] = page
- def add_widget(self, widget):
- if self.widget_index:
- raise Exception()
-
- self.widgets.append(widget)
-
- def add_widget_class(self, cls):
- self.widget_classes.add(cls)
-
- def get_widget(self, key):
- if not self.widget_index:
- index = dict()
-
- for widget in self.widgets:
- index[widget.path] = widget
-
- self.widget_index = index
-
- return self.widget_index.get(key)
-
- def add_parameter(self, param):
- if self.parameter_index:
- raise Exception()
-
- self.parameters.append(param)
-
- def get_parameter(self, page, key):
- if not self.parameter_index:
- index = dict()
-
- for param in self.parameters:
- if param.widget:
- index[(param.widget.page, param.path)] = param
-
- self.parameter_index = index
-
- param = self.parameter_index.get((page, key))
-
- # check for partial match for dictparameters
- if not param:
- if DictParameter.sep() in key:
- dict_key = key.split(DictParameter.sep(), 1)[0]
- param = self.parameter_index.get((page, dict_key))
-
- return param
-
def add_resource_dir(self, dir):
self.finder.add_dir(dir)
@@ -627,7 +553,7 @@
return url
def marshal_url_vars(self, separator=";"):
- params = self.page.get_saved_parameters(self)
+ params = self.page.get_page_parameters(self)
vars = list()
for param in params:
@@ -694,7 +620,7 @@
key = unquote(skey)
value = unquote_plus(svalue)
- param = self.app.get_parameter(self.page, key)
+ param = self.page.get_page_parameter_by_path(key)
if param:
if param.is_dictionary:
Modified: mgmt/trunk/wooly/python/wooly/forms.py
===================================================================
--- mgmt/trunk/wooly/python/wooly/forms.py 2009-03-18 18:45:18 UTC (rev 3170)
+++ mgmt/trunk/wooly/python/wooly/forms.py 2009-03-18 21:17:16 UTC (rev 3171)
@@ -36,7 +36,7 @@
if not self.origin.get(session):
self.origin.set(session, session.get_origin())
- params = set(session.page.get_saved_parameters(session))
+ params = set(session.page.get_page_parameters(session))
params.difference_update(self.form_params)
for param in params:
Modified: mgmt/trunk/wooly/python/wooly/pages.py
===================================================================
--- mgmt/trunk/wooly/python/wooly/pages.py 2009-03-18 18:45:18 UTC (rev 3170)
+++ mgmt/trunk/wooly/python/wooly/pages.py 2009-03-18 21:17:16 UTC (rev 3171)
@@ -6,8 +6,75 @@
strings = StringCatalog(__file__)
-class HtmlPage(Page):
+class WidgetPage(Page):
def __init__(self, app, name):
+ super(WidgetPage, self).__init__(app, name)
+
+ self.widget_classes = set()
+
+ self.__frame = self.FrameParameter(app, "frame")
+ self.add_parameter(self.__frame)
+
+ self.set_default_frame(self)
+
+ self.__saved_params = dict()
+
+ def init_widget(self, widget):
+ super(WidgetPage, self).init_widget(widget)
+
+ for cls in widget.__class__.__mro__:
+ self.widget_classes.add(cls)
+
+ if cls is Widget:
+ break
+
+ # XXX take "current" out of these
+ def set_current_frame(self, session, frame):
+ self.__frame.set(session, frame)
+ return frame
+
+ def get_current_frame(self, session):
+ return self.__frame.get(session)
+
+ def pop_current_frame(self, session):
+ frame = self.get_current_frame(session)
+ #print "Popping current frame", frame
+ self.set_current_frame(session, frame.frame)
+
+ def set_default_frame(self, frame):
+ self.__frame.default = frame
+
+ def get_page_parameters(self, session):
+ """
+ Gets a list of parameters saved for this page and its current
+ frame.
+
+ This, combined with [gs]et_current_frame, serves to discard
+ state that is out of scope. The current pattern is to
+ preserve the state of parameters in the current frame and all
+ of its ancestor frames.
+ """
+
+ frame = self.get_current_frame(session)
+
+ try:
+ params = self.__saved_params[frame]
+ except KeyError:
+ params = list()
+ self.save_parameters(session, params)
+ self.__saved_params[frame] = params
+
+ return params
+
+ class FrameParameter(Parameter):
+ def do_marshal(self, frame):
+ return frame.path
+
+ def do_unmarshal(self, path):
+ return self.widget.page.page_widgets_by_path.get(path)
+
+class HtmlPage(WidgetPage):
+ def __init__(self, app, name):
super(HtmlPage, self).__init__(app, name)
self.updates = self.UpdatesAttribute(app, "updates")
@@ -118,7 +185,7 @@
if not self.__css:
writer = Writer()
- for cls in sorted(self.app.widget_classes):
+ for cls in sorted(self.html_page.widget_classes):
strs = cls.get_module_strings()
if strs:
@@ -153,7 +220,7 @@
if not self.__javascript:
writer = Writer()
- for cls in sorted(self.app.widget_classes):
+ for cls in sorted(self.html_page.widget_classes):
strs = cls.get_module_strings()
if strs:
17 years, 1 month
rhmessaging commits: r3170 - mgmt/trunk/cumin/python/cumin.
by rhmessaging-commits@lists.jboss.org
Author: eallen
Date: 2009-03-18 14:45:18 -0400 (Wed, 18 Mar 2009)
New Revision: 3170
Modified:
mgmt/trunk/cumin/python/cumin/pool.py
Log:
better error checking for displaying status box when there are no slots
Modified: mgmt/trunk/cumin/python/cumin/pool.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/pool.py 2009-03-18 18:32:18 UTC (rev 3169)
+++ mgmt/trunk/cumin/python/cumin/pool.py 2009-03-18 18:45:18 UTC (rev 3170)
@@ -348,9 +348,10 @@
action = self.app.model.pool.poolstatus
record = action.get_stat_record(session, pool)
if record and ("idl" in record) and ("all" in record):
- writer = Writer()
- self.item_tmpl.render(writer, session, record)
- return writer.to_string()
+ if record["idl"] and record["all"]: # not None
+ writer = Writer()
+ self.item_tmpl.render(writer, session, record)
+ return writer.to_string()
def render_idle(self, session, record):
return record["idl"]
17 years, 1 month
rhmessaging commits: r3169 - mgmt/trunk/cumin/python/cumin.
by rhmessaging-commits@lists.jboss.org
Author: eallen
Date: 2009-03-18 14:32:18 -0400 (Wed, 18 Mar 2009)
New Revision: 3169
Added:
mgmt/trunk/cumin/python/cumin/visualizations.py
mgmt/trunk/cumin/python/cumin/visualizations.strings
Log:
New slot vis files
Added: mgmt/trunk/cumin/python/cumin/visualizations.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/visualizations.py (rev 0)
+++ mgmt/trunk/cumin/python/cumin/visualizations.py 2009-03-18 18:32:18 UTC (rev 3169)
@@ -0,0 +1,180 @@
+import logging
+
+from wooly.widgets import *
+from wooly import *
+from wooly.forms import *
+from wooly.resources import *
+from wooly.tables import *
+
+from widgets import *
+from stat import *
+from parameters import *
+from formats import *
+from util import *
+from job import *
+
+strings = StringCatalog(__file__)
+
+class SlotMap(Widget):
+ def __init__(self, app, name):
+ super(SlotMap, self).__init__(app, name)
+
+ self.slot_info = self.SlotInfo(app, "slot_info")
+ self.add_child(self.slot_info)
+
+ self.slot_legend = self.SlotLegend(app, "slot_legend")
+ self.add_child(self.slot_legend)
+
+ self.wait = self.PleaseWait(app, "please_wait")
+ self.add_child(self.wait)
+
+ def get_args(self, session):
+ return self.frame.get_args(session)
+
+ def render_href(self, session, object):
+ params = list()
+ cls = self.app.model.get_class_by_object(object).cumin_name
+ params.append("class=%s" % cls)
+ params.append("id=%s" % object.id)
+ params.append("zl=1") # zoom level
+ params.append("zx=0") # zoom left
+ params.append("zy=0") # zoom top
+
+ return "slots.png?" + ";".join(params)
+
+ def get_title_name(self, session, object):
+ return str(object.id)
+
+ def render_title(self, session, object):
+ return "Slots on '%s'" % self.get_title_name(session, object)
+
+ def render_job_index_param(self, session, *args):
+ return "xargs"
+
+ def render_slot_job_url(self, session, *args):
+ job = Identifiable("XXX")
+ return self.page.main.pool.job.get_href(session, job)
+
+ def render_slot_clip_size(self, session, *args):
+ return 400
+
+ class PleaseWait(CuminForm):
+ def __init__(self, app, name):
+ super(SlotMap.PleaseWait, self).__init__(app, name)
+
+ self.__cancel = self.Cancel(app, "cancel")
+ self.__cancel.set_tab_index(201)
+ self.add_child(self.__cancel)
+
+ def get_modal(self, session):
+ return False
+
+ class Cancel(FormButton):
+ def render_class(self, session, *args):
+ return "cancel"
+
+ def render_content(self, session, *args):
+ return "Cancel"
+
+ def render_onclick(self, session, *args):
+ return "cancel_wait"
+
+ class SlotLegend(Widget):
+ def __init__(self, app, name):
+ super(SlotMap.SlotLegend, self).__init__(app, name)
+
+ self.states = self.SlotStates(app, "slot_states")
+ self.add_child(self.states)
+
+ self.activities = self.SlotActivities(app, "slot_activities")
+ self.add_child(self.activities)
+
+ class SlotStates(ItemSet):
+ states = ("Unclaimed", "Claimed", "Owner", "Matched", "Preempting")
+
+ def do_get_items(self, session):
+ return self.states
+
+ def render_initial(self, session, state):
+ return state[0]
+
+ def render_title(self, session, state):
+ return state
+
+ class SlotActivities(ItemSet):
+ activities = [("Idle", "clear"),
+ ("Busy", "green"),
+ ("Suspended", "red"),
+ ("Vacating", "orange"),
+ ("Killing", "blue"),
+ ("Benchmarking", "yellow"),
+ ("Unknown", "grey")]
+
+ def do_get_items(self, session):
+ return self.activities
+
+ def render_title(self, session, activity):
+ return activity[0]
+
+ def render_href(self, session, activity):
+ params = list()
+ params.append("dot=%s" % activity[0])
+
+ return "slots.png?" + ";".join(params)
+
+ def render_dot_size(self, session, activity):
+ return 12
+
+ class SlotInfo(ItemSet):
+ display_names = {"jid": "jid", "job_id": "Job ID",
+ "system": "System", "machine": "Machine",
+ "state": "State", "activity": "Activity",
+ "name": "Name"}
+
+ def __init__(self, app, name):
+ super(SlotMap.SlotInfo, self).__init__(app, name)
+
+ self.info_index = IntegerParameter(app, "i")
+ self.add_parameter(self.info_index)
+
+ self.info_div_tmpl = Template(self, "bg_html")
+
+ def get_args(self, session):
+ return self.frame.get_args(session)
+
+ def do_render(self, session, *args):
+ object = args[0]
+ info_index = self.info_index.get(session)
+ if info_index is not None:
+ #print "rendering slot info for %i" % info_index
+ cls = self.app.model.get_class_by_object(object)
+ action = cls.get_visualization_action()
+ slot_info = action.get_boxes(session, object)
+ writer = Writer()
+ self.info_div_tmpl.render(writer, session, slot_info[info_index])
+ return writer.to_string()
+ else:
+ return super(SlotMap.SlotInfo, self).do_render(session, *args)
+
+ def do_get_items(self, session, slot):
+ return ((self.display_names[x], slot[x])
+ for x in slot if x in self.display_names)
+
+ def render_slot_info_url(self, session, *args):
+ return self.page.get_update_url(session, [self])
+
+ def render_slot_info_index(self, session, *args):
+ return self.info_index.path
+
+ def render_title(self, session, item):
+ return item[0]
+
+ def render_value(self, session, item):
+ return item[1]
+
+ def render_job_id(self, session, item):
+ return item[0] == "jid" and "id='job_id'" or ""
+
+ def render_row_class(self, session, item):
+ return item[0] == "jid" and "class='hidden_row'" or ""
+
Added: mgmt/trunk/cumin/python/cumin/visualizations.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/visualizations.strings (rev 0)
+++ mgmt/trunk/cumin/python/cumin/visualizations.strings 2009-03-18 18:32:18 UTC (rev 3169)
@@ -0,0 +1,1225 @@
+[SlotMap.javascript]
+var vis;
+(function() {
+ vis = new Visualization();
+ var slot_clip_left;
+ var slot_clip_top;
+ var slot_zoom;
+ var slot_last_index;
+ var slot_info_timer;
+ var slot_hover_timer;
+ var slot_png_timer;
+ var slot_zoom_initialized;
+ var slot_center_index;
+
+ function Visualization() {
+ slot_clip_left = 0;
+ slot_clip_top = 0;
+ slot_zoom = 1;
+ slot_last_index = -1;
+ slot_info_timer = null;
+ slot_hover_timer = null;
+ slot_png_timer = null;
+ slot_zoom_initialized = false;
+ slot_center_index = -1;
+
+ this.pan_left = function () {
+ if (slot_clip_left == 0) return;
+ var now = new Date();
+ animate_pan(slot_clip_left, Math.min(Math.floor(slot_clip_size / 1.1), -slot_clip_left), (now-0), "slot_clip_left");
+ }
+ this.pan_right = function () {
+ var to_pan = Math.floor(slot_clip_size / 1.1);
+ if (slot_clip_left - slot_clip_size - to_pan < -slot_map_info.width) {
+ to_pan = slot_map_info.width - slot_clip_size + slot_clip_left;
+ }
+ var now = new Date();
+ animate_pan(slot_clip_left, -to_pan, (now-0), "slot_clip_left");
+ }
+ this.pan_up = function () {
+ if (slot_clip_top == 0) return;
+ var now = new Date();
+ animate_pan(slot_clip_top, Math.min(Math.floor(slot_clip_size / 1.1), -slot_clip_top), (now-0), "slot_clip_top");
+ }
+ this.pan_down = function () {
+ if (slot_map_info.height < slot_clip_size) return;
+
+ var to_pan = Math.floor(slot_clip_size / 1.1);
+ if (slot_clip_top - slot_clip_size - to_pan < -slot_map_info.height) {
+ to_pan = slot_map_info.height - slot_clip_size + slot_clip_top;
+ }
+ var now = new Date();
+ animate_pan(slot_clip_top, -to_pan, (now-0), "slot_clip_top");
+ }
+
+
+ // in case server stops and then restarts, reget the images
+ this.img_error = function (oImg) {
+ stop_auto_updates();
+ var oZooming = document.getElementById("slot_zooming");
+ if (oZooming) {
+ oZooming.style.display = "none";
+ }
+ oImg.style.visibility = "hidden"; // hide broken image indicator
+ slot_map_info.size = 0;
+ slot_map_info.width = 1;
+ slot_map_info.height = 1;
+ slot_map_info.rows = 1;
+ slot_map_info.cols = 1;
+ slot_map_info.count = 0;
+ slot_png_timer = setInterval(update_png, 10000);
+ }
+ this.img_loaded = function (oImg) {
+ stop_auto_updates();
+ var oZooming = document.getElementById("slot_zooming");
+ if (oZooming) {
+ oZooming.style.display = "none";
+ }
+
+ if (oImg) {
+ oImg.style.visibility = "visible";
+ slot_cookie_info();
+ oImg.width = slot_map_info.width;
+ oImg.height = slot_map_info.height;
+ set_pan("slot_panup", "width", slot_map_info.size * slot_map_info.cols, this.pan_up);
+ set_pan("slot_pandown", "width", slot_map_info.size * slot_map_info.cols, this.pan_down);
+ set_pan("slot_panleft", "height", slot_map_info.size * slot_map_info.rows, this.pan_left);
+ set_pan("slot_panright", "height", slot_map_info.size * slot_map_info.rows, this.pan_right);
+
+ var oMap = document.getElementById(slot_current_id);
+ if (oMap) {
+ oMap.style.width = Math.min(oImg.width, slot_clip_size) + "px";
+ oMap.style.height = Math.min(oImg.height, slot_clip_size) + "px";
+ if ((slot_map_info.size * slot_map_info.rows < slot_clip_size) &&
+ (slot_map_info.size * slot_map_info.cols < slot_clip_size))
+ oMap.style.borderColor = "transparent";
+ else
+ oMap.style.borderColor = "#CCCCCC";
+
+ }
+ var oGlass = document.getElementById("slot_glass");
+ if (oGlass) {
+ oGlass.style.width = Math.min(oImg.width, slot_clip_size) + "px";
+ oGlass.style.height = Math.min(oImg.height, slot_clip_size) + "px";
+ }
+ if (!slot_zoom_initialized)
+ initialize_zoom();
+
+ animate_zoom_to(slot_zoom);
+ var oControls = document.getElementById("slot_controls");
+ if (oControls) {
+ var oMap = document.getElementById(slot_current_id);
+ oControls.style.left = (oMap.offsetLeft + oMap.offsetWidth - oControls.offsetWidth) + "px";
+ //oControls.style.left = (420 - oControls.offsetWidth) + "px";
+ }
+ refire_info();
+ }
+ center_on_index();
+ draw_clipped();
+ slot_png_timer = setInterval(update_png, 6000);
+ }
+
+ this.upGlass = function (e) {
+ if (!e) var e = window.event;
+ var oGlass = document.getElementById("slot_glass");
+ if (oGlass) {
+ if (oGlass.dragging) {
+ oGlass.dragging = false;
+ }
+ }
+ }
+
+ this.moveGlass = function (e) {
+ if (slot_map_info.size == 0) return;
+ if (!e) var e = window.event;
+ var oGlass = document.getElementById("slot_glass");
+ if (oGlass) {
+ if (oGlass.dragging) {
+ var posxy = get_event_pos(e);
+ if ((posxy.x - oGlass.down_pos.x > 0) || (posxy.y - oGlass.down_pos.y > 0))
+ oGlass.down_pos = {x: posxy.x - slot_clip_left, y: posxy.y - slot_clip_top};
+
+ slot_clip_left = Math.min(posxy.x - oGlass.down_pos.x, 0);
+ slot_clip_top = Math.min(posxy.y - oGlass.down_pos.y, 0);
+ oGlass.drug = true;
+
+ draw_clipped();
+ if (e.preventDefault)
+ e.preventDefault();
+ return false;
+ }
+ }
+
+ var rpos = get_relative_event_pos(e);
+ if (rpos) {
+ get_slot_info(rpos.x, rpos.y);
+ }
+ }
+
+ this.downGlass = function (e) {
+ if (!e) var e = window.event;
+
+ var oGlass = document.getElementById("slot_glass");
+ if (oGlass) {
+ oGlass.dragging = true;
+ var posxy = get_event_pos(e);
+ oGlass.down_pos = {x: posxy.x - slot_clip_left, y: posxy.y - slot_clip_top};
+ clear_hover();
+ hide_info();
+ }
+ return false;
+ }
+
+ this.outGlass = function outGlass(e) {
+ if (!e) var e = window.event;
+ clear_hover();
+ hide_info();
+ }
+
+ this.zoom_in_slots = function (posxy) {
+ if (slot_zoom >= get_max_zoom()) return;
+ var click_info = get_index(posxy.x, posxy.y);
+ slot_center_index = click_info.index;
+ do_zoom(slot_zoom + 1);
+ }
+
+ this.fire_slot_info = function (index) {
+ slot_last_index = index;
+ slot_info_timer = null;
+ do_info_request(index);
+ }
+
+ }
+
+ function slot_zoom_to(e) {
+ if (!e) var e = window.event;
+ var targ = get_event_target(e);
+ var level = parseInt(targ.level, 10);
+
+ get_center_index();
+ do_zoom(level);
+
+ if (e.stopPropagation)
+ e.stopPropagation()
+ else if (e.cancelBubble)
+ e.cancelBubble = true;
+ }
+
+ function do_zoom(level) {
+ var old_zoom = slot_zoom;
+ slot_zoom = level;
+
+ stop_auto_updates();
+ var oZooming = document.getElementById("slot_zooming");
+ if (oZooming) {
+ oZooming.style.display = "block";
+ var oMap = document.getElementById(slot_current_id);
+ if (oMap) {
+ oZooming.style.width = oMap.offsetWidth + "px";
+ }
+ }
+ var oImg = document.images[slot_current_id];
+ if (oImg) {
+ var src = oImg.src;
+ src = replace_value(src, "zl", level, ";");
+ src = replace_value(src, "zx", slot_clip_left, ";");
+ src = replace_value(src, "zy", slot_clip_top, ";");
+
+ src = refreshTime(src);
+ oImg.src = src;
+ }
+
+ animate_zoom_to(level);
+ return false;
+ }
+
+ function animate_zoom_to(level) {
+ var oPos = document.getElementById("zoom_pos");
+ if (oPos) {
+ var original_x = oPos.offsetLeft;
+ var now = new Date();
+ var x_amount = ((level - 1) * 13) - original_x;
+ animate_zoom_pos(original_x, (now-0), x_amount)
+ }
+ }
+ function animate_zoom_pos(original_x, original_time, x_amount) {
+ var oPos = document.getElementById("zoom_pos");
+ if (oPos) {
+ var now = new Date();
+ var delta = (now - original_time) / 400.0;
+ var partial = 1;
+ if (delta < 1)
+ partial = Math.sin(Math.PI/2 * delta);
+ oPos.style.left = Math.floor(original_x + x_amount * partial) + "px";
+
+ if (delta < 1)
+ setTimeout(function(){ animate_zoom_pos(original_x, original_time, x_amount) }, 10);
+ }
+ }
+
+ function stop_auto_updates() {
+ if (slot_png_timer) {
+ clearInterval(slot_png_timer);
+ slot_png_timer = null;
+ }
+ }
+
+ function update_png() {
+ stop_auto_updates();
+ updateChart(slot_current_id, null);
+ }
+
+ function set_pan(id, which, value, fn) {
+ var obj = document.getElementById(id);
+ if (obj) {
+ if (value < slot_clip_size) {
+ eval("obj.style." + which + " = '" + Math.min(value, slot_clip_size) + "px'");
+ obj.style.visibility = "hidden";
+ obj.onclick = null;
+ } else {
+ eval("obj.style." + which + " = '" + Math.min(value, slot_clip_size) + "px'");
+ obj.style.visibility = "visible";
+ obj.onclick = fn;
+ }
+ }
+ }
+
+
+ function slot_cookie_info() {
+ var slot_info = get_cookie("slot_info");
+ if (slot_info) {
+ var vals = slot_info.split("|");
+ if (vals.length == 6) {
+ slot_map_info.size = parseInt(vals[0], 10);
+ slot_map_info.width = parseInt(vals[1], 10);
+ slot_map_info.height = parseInt(vals[2], 10);
+ slot_map_info.count = parseInt(vals[3], 10);
+ slot_map_info.rows = parseInt(vals[4], 10);
+ slot_map_info.cols = parseInt(vals[5], 10);
+ }
+ }
+ }
+
+ function center_on_index() {
+ if (slot_center_index == -1) return;
+
+ var row = slot_center_index % slot_map_info.cols;
+ var col = Math.floor(slot_center_index / slot_map_info.cols);
+ var x = col * slot_map_info.size + slot_map_info.size / 2;
+ var y = row * slot_map_info.size + slot_map_info.size / 2;
+
+ var cl = (Math.min(slot_clip_size, slot_map_info.width) / 2) - x;
+ var ct = (Math.min(slot_clip_size, slot_map_info.height) / 2) - y;
+
+ if (slot_map_info.width + cl < slot_clip_size)
+ cl = slot_clip_size - slot_map_info.width;
+
+ if (slot_map_info.height + ct < slot_clip_size)
+ ct = slot_clip_size - slot_map_info.height;
+
+ if (cl > 0) cl = 0;
+ if (ct > 0) ct = 0;
+
+ slot_clip_left = Math.floor(cl);
+ slot_clip_top = Math.floor(ct);
+ slot_center_index = -1;
+ }
+
+ function get_center_index() {
+ var rx = Math.min(slot_clip_size, slot_map_info.width) / 2;
+ var ry = Math.min(slot_clip_size, slot_map_info.height) / 2;
+
+ var click_info = get_index(rx, ry);
+ if (click_info)
+ slot_center_index = click_info.index;
+ }
+
+ function get_max_zoom() {
+ // allow to zoom until each slot is at least 28px wide
+ return Math.ceil(28 / (slot_map_info.size / slot_zoom));
+ }
+ function initialize_zoom() {
+ var max_zoom = get_max_zoom();
+ var oZoom = document.getElementById("zoom_levels");
+ if ((oZoom) && (max_zoom > 1)) {
+ var oDiv, oText, oNode;
+ for (var i=0; i<max_zoom; i++) {
+ var oDiv = document.createElement("div");
+ if (i == 0) {
+ oDiv.className = "zoom_first";
+ oDiv.onclick = slot_zoom_to;
+ oDiv.level = i+1;
+ set_text(oDiv, (i+1)+ "", "zoom_node");
+ } else if (i == max_zoom - 1) {
+ oDiv.className = "zoom_last";
+ oDiv.onclick = slot_zoom_to;
+ oDiv.level = i+1;
+ set_text(oDiv, i+1, "zoom_node_last");
+ } else {
+ oDiv.className = "zoom_middle_left";
+ oDiv.onclick = slot_zoom_to;
+ oDiv.level = i+1;
+ oZoom.appendChild(oDiv);
+ oDiv = document.createElement("div");
+ oDiv.className = "zoom_middle_right";
+ oDiv.onclick = slot_zoom_to;
+ oDiv.level = i+1;
+ set_text(oDiv, (i+1)+ "", "zoom_node");
+ }
+ oZoom.appendChild(oDiv);
+ }
+ } else {
+ var oControls = document.getElementById("slot_controls");
+ if (oControls) {
+ oControls.style.display = "none";
+ }
+ }
+ var oVis = document.getElementById("slot_visualization");
+ if (oVis) {
+ oVis.style.visibility = "visible";
+ }
+ slot_zoom_initialized = true;
+
+ function set_text(odiv, text, className) {
+ var oText = document.createElement("div");
+ var oNode = document.createTextNode(text+"");
+ oText.className = className;
+ oText.appendChild(oNode);
+ odiv.appendChild(oText);
+ oText.onclick = slot_zoom_to;
+ oText.level = text;
+ }
+ }
+
+ function draw_clipped() {
+
+ var clip_bottom;
+ var clip_right;
+ if (slot_map_info.width < slot_clip_size) {
+ clip_bottom = slot_map_info.height;
+ clip_right = slot_map_info.width;
+ slot_clip_left = 0;
+ slot_clip_top = 0;
+ } else {
+ var iZoom = slot_zoom;
+ var clip_width = slot_clip_size;
+ var clip_height = slot_clip_size;
+ clip_bottom = clip_height - slot_clip_top;
+ clip_right = clip_width - slot_clip_left;
+
+ if (clip_right > slot_map_info.width) {
+ slot_clip_left += (clip_right - slot_map_info.width);
+ clip_right = slot_map_info.width;
+ }
+ if (clip_bottom > slot_map_info.height) {
+ slot_clip_top = Math.min(clip_height - slot_map_info.height, 0);
+ clip_bottom = slot_map_info.height;
+ }
+ }
+
+ var oPng = document.getElementById("slot_png");
+ if (oPng) {
+ oPng.style.left = slot_clip_left + "px";
+ oPng.style.top = slot_clip_top + "px";
+ oPng.style.clip = "rect(" + (-slot_clip_top) + "px " + clip_right + "px " + clip_bottom + "px " + (-slot_clip_left) + "px)";
+ }
+ }
+
+
+ function animate_pan(original_edge, move, timer, which) {
+ var now = new Date();
+ var delta = (now - timer) / 400.0;
+ var expression = "=Math.floor(original_edge + move";
+ if (delta < 1) {
+ expression += " * Math.sin(Math.PI/2 * delta)";
+ }
+ expression += ")";
+ eval(which + expression);
+ draw_clipped();
+ if (delta < 1)
+ setTimeout( function () {animate_pan(original_edge, move, timer, which) }, 10);
+
+ }
+
+ function clear_hover() {
+ if (slot_info_timer) {
+ clearTimeout(slot_info_timer);
+ slot_info_timer = null;
+ slot_last_index = -1;
+ }
+ oHover = document.getElementById("slot_hover");
+ if (oHover) {
+ oHover.style.visibility = "hidden";
+ }
+ }
+ function hide_info() {
+ oInfo = get_slot_info_elem();
+ if (oInfo) {
+ oInfo.style.visibility = "hidden";
+ }
+ slot_last_index = -1;
+ }
+
+ function get_index(x, y) {
+ var width = slot_map_info.size;
+ var pngrow = Math.floor((y - slot_clip_top) / width);
+ var pngcol = Math.floor((x - slot_clip_left) / width);
+ if ((pngcol < slot_map_info.cols) && (pngrow < slot_map_info.rows)) {
+ var index = pngrow * slot_map_info.cols + pngcol;
+ if (index < slot_map_info.count)
+ return {"index": index, "row": pngrow, "col": pngcol};
+ }
+ return null;
+ }
+
+ function get_slot_info(rx, ry) {
+
+ var click_info = get_index(rx, ry);
+ if (click_info) {
+ if (click_info.index != slot_last_index) {
+ if (slot_info_timer) {
+ clearTimeout(slot_info_timer);
+ slot_info_timer = null;
+ }
+ if (slot_hover_timer) {
+ clearTimeout(slot_hover_timer);
+ slot_hover_timer = null;
+ }
+ slot_info_timer = setTimeout( function() { vis.fire_slot_info(click_info.index) }, 500);
+ animate_hover(0, click_info.row, click_info.col);
+ oInfo = get_slot_info_elem();
+ if (oInfo) {
+ oInfo.style.display = "none";
+ }
+ }
+ }
+ }
+ function animate_hover(leg, row, col) {
+ var oHover = document.getElementById("slot_hover");
+ if (oHover) {
+ if (slot_hover_timer) {
+ clearTimeout(slot_hover_timer);
+ slot_hover_timer = null;
+ }
+ var width = slot_map_info.size;
+ if (width == 0) return;
+ var rx = col * width + slot_clip_left;
+ var ry = row * width + slot_clip_top;
+ oHover.style.width = (width-1) + "px";
+ oHover.style.height = (width-1) + "px";
+
+ switch (leg) {
+ case 0:
+ oHover.style.left = rx + "px";
+ oHover.style.top = ry + "px";
+ oHover.style.width = width + "px";
+ oHover.style.height = width + "px";
+ oHover.style.borderColor = "red pink pink pink";
+ oHover.style.visibility = "visible";
+ if ((rx < 0) || (ry < 0) || (rx + width > slot_clip_size) || (ry + width > slot_clip_size)) {
+ var cx = (rx < 0) ? rx : 0;
+ var cy = (ry < 0) ? ry : 0;
+ var cw = (rx + width > slot_clip_size) ? slot_clip_size - rx : width + 1;
+ var ch = (ry + width > slot_clip_size) ? slot_clip_size - ry : width + 1;
+ oHover.style.clip = "rect(" + (-cy) + "px " + (cw) + "px " + (ch) + "px " + (-cx) + "px)";
+ } else {
+ oHover.style.clip = "rect(0px " + (width+1) + "px " + (width+1) + "px 0px)";
+ }
+ slot_hover_timer = setTimeout( function() {animate_hover(1)}, 500/3);
+ break;
+ case 1: oHover.style.borderColor = "red red pink pink";
+ slot_hover_timer = setTimeout( function() {animate_hover(2)}, 500/3);
+ break;
+ case 2: oHover.style.borderColor = "red red red pink";
+ slot_hover_timer = setTimeout( function() {animate_hover(3)}, 500/3);
+ break;
+ case 3: oHover.style.borderColor = "red red red red";
+ break;
+ }
+ }
+ }
+ function get_slot_info_elem() {
+ return document.getElementById(slot_info_id);
+ }
+
+ function refire_info() {
+ if (slot_last_index > -1) {
+ do_info_request(slot_last_index)
+ }
+ }
+
+ function do_info_request(index) {
+ args = slot_info_url.split("?");
+ var session = get_value(args[1], "session", ";")
+ sess = unescape(session);
+ sess = sess + ";" + slot_info_index + "=" + index;
+ sess = escape(sess);
+ var newreq = replace_value(slot_info_url, "session", sess, ";");
+
+ wooly.directUpdate(newreq, got_slot_info, 0, {index: index});
+ }
+
+ function got_slot_info(xhtml, args) {
+ if (slot_last_index == -1) return;
+ var oInfo = get_slot_info_elem();
+ var for_jid = null;
+ if (oInfo) {
+ oInfo.style.display = "none";
+ if (oInfo.for_jid) {
+ for_jid = oInfo.for_jid;
+ oInfo.for_jid = null;
+ }
+ }
+ wooly.updatePage(xhtml);
+ var oInfo = get_slot_info_elem();
+ if (oInfo) {
+ oInfo.click_index = args.index;
+ oInfo.for_jid = null;
+ if (for_jid) {
+ clicks.doClick(for_jid.x, for_jid.y);
+ return;
+ }
+
+ promote_to_body(oInfo); // so position is absolute to entire page
+
+ oInfo.style.left = "-1000px";
+ oInfo.style.visibility = "hidden";
+ oInfo.style.display = "block";
+
+ var oMap = document.getElementById(slot_current_id);
+ if (oMap) {
+ var abs_pos = findPos(oMap);
+
+ // top of clicked slot is here
+ var y = Math.floor(args.index / slot_map_info.cols) * slot_map_info.size + slot_clip_top;
+
+ // candidate pos for popup
+ var top = (abs_pos.y + y) + Math.floor(slot_map_info.size * 1.5);
+
+ // if off the bottom of the map
+ if (top + oInfo.offsetHeight > abs_pos.y + oMap.offsetHeight) {
+ // position popup above clicked slot
+ top = (abs_pos.y + y) - oInfo.offsetHeight - Math.floor(slot_map_info.size * .5);
+ }
+ oInfo.style.top = top + "px";
+ oInfo.style.left = abs_pos.x + "px";
+ }
+ oInfo.style.visibility = "visible";
+ }
+ }
+
+
+}())
+
+
+var clicks;
+(function() {
+ clicks = new Clicks();
+
+ function Clicks() {
+ this.doubleclick_when = 0;
+ this.click_when = 0;
+ this.click_handle = null;
+
+ this.doMouseDown = function(e) {
+ if (!e) var e = window.event;
+ var which = e.type;
+ switch (which) {
+ case "click":
+ // If we've just had a doubleclick then ignore it
+ if (hadDoubleClick()) return false;
+ // Otherwise set timer to act. It may be preempted by a doubleclick.
+ d = new Date();
+ this.click_when = d.getTime();
+ var rpos = get_relative_event_pos(e);
+ if (rpos) {
+ this.click_handle = setTimeout( function() {clicks.doClick(rpos.x, rpos.y)}, 250);
+ break;
+ }
+ case "dblclick":
+ doDoubleClick(e);
+ break;
+ default:
+ }
+ }
+
+ this.doClick = function(x, y) {
+ // preempt if DC occurred after original click.
+ if (this.click_when - this.doubleclick_when <= 0) {
+ return false;
+ }
+ var oGlass = document.getElementById("slot_glass");
+ if (oGlass) {
+ if (oGlass.drug) {
+ oGlass.drug = false;
+ return false;
+ }
+ }
+ var click_info = get_index(x, y);
+ var oInfo = get_slot_info_elem();
+ if (oInfo && click_info) {
+ if ((typeof oInfo.click_index != "undefined") &&
+ (oInfo.click_index == click_info.index)) {
+ // we already fetched the info for this slot
+ var oInfoCell = document.getElementById("job_id");
+ if (oInfoCell) {
+ var jid = oInfoCell.innerHTML;
+ if (jid != "") {
+ go_to_job(jid);
+ return false;
+ }
+ }
+ } else {
+ // fetch the slot info so we can get the job id
+ oInfo.for_jid = {fetching: true, x: x, y: y};
+ vis.fire_slot_info(click_info.index);
+ }
+ }
+ function go_to_job(jid) {
+ var url = show_slot_job_url.replace("XXX", jid+"");
+ window.location.href = url;
+ show_wait();
+ }
+ }
+ }
+
+ function hadDoubleClick() {
+ var d = new Date();
+ var now = d.getTime();
+ if ((now - this.doubleclick_when) < 100) {
+ return true;
+ }
+ return false;
+ }
+
+ function doDoubleClick(e) {
+ var now = new Date();
+ this.doubleclick_when = now.getTime();
+ if (this.click_handle != null) {
+ clearTimeout(this.click_handle); // Clear pending Click
+ this.click_handle = null;
+ }
+ if (!e) var e = window.event;
+ var posxy = get_relative_event_pos(e);
+ vis.zoom_in_slots(posxy);
+ }
+}())
+
+/* generic get value from cookie */
+function get_cookie(name) {
+ return get_value(document.cookie, name, ";");
+}
+
+/* generic get value from string */
+function get_value(s, name, sep) {
+ var name_plus = name + "=";
+ var crumbs = s.split(sep);
+ // splitting to avoid false match on substring:
+ // ex: bigfoo=duh;foo=blah;
+ for(var i=0; i < crumbs.length; i++) {
+ var c = crumbs[i];
+ while (c.charAt(0) == ' ') {
+ c = c.substring(1, c.length);
+ }
+
+ if (c.indexOf(name_plus) == 0) {
+ return c.substring(name_plus.length,c.length);
+ }
+ }
+ return null;
+}
+
+/* generic replace a value in a name=value; string */
+function replace_value(s, name, value, sep) {
+ var name_index = s.indexOf(name+"=");
+ if (name_index > -1) {
+ var sep_index = s.indexOf(sep, name_index);
+ if (sep_index == -1) { // end of string
+ sep_index = s.length;
+ }
+ var s1 = s.substring(0, name_index + name.length + 1);
+ var s2 = value + "";
+ var s3 = s.substring(sep_index);
+ return s1 + s2 + s3;
+ }
+ return s;
+}
+
+/* get the absolute position of something */
+function findPos(obj) {
+ var curleft = curtop = 0;
+ if (obj.offsetParent) {
+ do {
+ curleft += obj.offsetLeft;
+ curtop += obj.offsetTop;
+ } while (obj = obj.offsetParent);
+ return {x: curleft, y: curtop};
+ }
+}
+
+/* get the absolute event position */
+function get_event_pos(e) {
+ if (e.pageX || e.pageY) {
+ posx = e.pageX;
+ posy = e.pageY;
+ }
+ else if (e.clientX || e.clientY) {
+ posx = e.clientX + document.body.scrollLeft
+ + document.documentElement.scrollLeft;
+ posy = e.clientY + document.body.scrollTop
+ + document.documentElement.scrollTop;
+ }
+ return {"x": posx, "y": posy};
+}
+
+/* find out what element the event was the event target */
+function get_event_target(e) {
+ var targ = null;
+ if (e.target)
+ targ = e.target;
+ else if (e.srcElement)
+ targ = e.srcElement;
+ if (targ.nodeType == 3) // avoid Safari textNode bug
+ targ = targ.parentNode;
+ return targ;
+}
+
+/* get the event position relatave to the event target */
+function get_relative_event_pos(e) {
+ var targ = get_event_target(e);
+ if (targ) {
+ var pxy = findPos(targ);
+ var posxy = get_event_pos(e);
+
+ var rx = posxy.x - pxy.x - 2;
+ var ry = posxy.y - pxy.y - 2;
+ return {x: rx, y: ry};
+ }
+}
+
+/* move an element to the body to break out of any relative positioning */
+function promote_to_body(obj) {
+ if (obj) {
+ var bodyList = document.getElementsByTagName("body");
+ if (bodyList) {
+ bodyList[0].appendChild(obj);
+ }
+ }
+}
+
+
+[SlotMap.css]
+div#slot_hover {
+ visibility: hidden;
+ position: absolute;
+ border: 1px solid pink;
+ left: 0;
+ top: 0;
+ z-index: 10;
+ width: 28px;
+ height: 28px;
+ -moz-border-radius: 50%;
+}
+div#slot_zooming {
+ width: 400px;
+ height: 400px;
+ position: absolute;
+ left:0;
+ top:0;
+ z-index:200;
+ text-align: center;
+ background-color: white;
+ overflow: hidden;
+ opacity: 0.5;
+ -moz-opacity: 0.5;
+ display: none;
+}
+div#slot_zooming p {
+ margin: 0;
+ padding: 140px 0 0 0;
+}
+div#slot_controls {
+ font-size: 0.8em;
+ float: left;
+ position: relative;
+ left: 0px;
+ top: 11px;
+ z-index: 1;
+}
+
+div#slot_panleft {
+ float: left;
+ background: url(resource?name=pan-left.png) scroll no-repeat center;
+ width: 18px;
+ height: 0px;
+}
+div#slot_panright {
+ float: left;
+ background: url(resource?name=pan-right.png) scroll no-repeat center;
+ width: 18px;
+ height: 0px;
+}
+div#slot_panup {
+ clear: both;
+ background: url(resource?name=pan-up.png) scroll no-repeat center;
+ height: 18px;
+ width: 0px;
+ position: relative;
+ left: 18px;
+ z-index:0;
+}
+div#slot_pandown {
+ clear: left;
+ background: url(resource?name=pan-down.png) scroll no-repeat center;
+ height: 18px;
+ width: 0px;
+ position: relative;
+ left: 18px;
+}
+
+div.slot_map {
+ background-color: white;
+ border: 1px solid #CCCCCC;
+ float: left;
+ height: 0px;
+ overflow: hidden;
+ position:relative;
+ width: 0px;
+}
+div#slot_png {
+ clip: rect(0 400px 400px 0);
+ position:absolute;
+ z-index: 0;
+}
+div#slot_glass {
+ height: 0px;
+ left: 0px;
+ position:absolute;
+ top: 0px;
+ width: 0px;
+ z-index: 100;
+}
+div#slot_visualization {
+ position: relative;
+ visibility: hidden;
+}
+div.zoom_node {
+ background-color: white;
+ position: absolute;
+ left: -4px;
+ top: -8px;
+ color: #0066CC;
+}
+div.zoom_node_last {
+ background-color: white;
+ position: absolute;
+ left: 2px;
+ top: -8px;
+ color: #0066CC;
+}
+div.zoom_first {
+ width: 6px;
+ height: 15px;
+ border-bottom: 1px solid black;
+ border-left: 1px solid black;
+ float: left;
+ position: relative;
+ margin-left: 0.5em;
+ cursor: pointer;
+}
+div.zoom_last {
+ width: 6px;
+ height: 15px;
+ border-bottom: 1px solid black;
+ border-right: 1px solid black;
+ float: left;
+ position: relative;
+ margin-right: 0.5em;
+ cursor: pointer;
+}
+div.zoom_middle_right {
+ width: 6px;
+ height: 15px;
+ border-bottom: 1px solid black;
+ border-left: 1px solid black;
+ float: left;
+ position: relative;
+ cursor: pointer;
+}
+div.zoom_middle_left {
+ width: 6px;
+ height: 15px;
+ border-bottom: 1px solid black;
+ float: left;
+ cursor: pointer;
+}
+div#zoom_text {
+ margin-right: 1em;
+ float:left;
+}
+div#zoom_levels {
+ position:relative;
+ float: left;
+}
+div#zoom_pos {
+ background: url(slots.png?dot=Busy) scroll no-repeat center;
+ width: 12px;
+ height: 12px;
+ position: absolute;
+ top: 10px;
+ z-index: 4;
+}
+
+[SlotMap.html]
+<div id="slot_visualization">
+ <h2>{title}</h2>
+ <div id="slot_controls">
+ <div id="zoom_text">Zoom</div><div id="zoom_levels"><div id="zoom_pos"></div></div><div style="clear:left;"><!-- --></div>
+ </div>
+
+ <div id="slot_panup" onclick="vis.pan_up()"></div>
+ <div id="slot_panleft" onclick="vis.pan_left()"></div>
+ <div class="slot_map" id="{id}">
+ <div id="slot_glass"><!-- mouse target to prevent selecting/dragging image --></div>
+ <div id="slot_png">
+ <img name="{id}" src="{href}" border="0" onload="vis.img_loaded(this)" onerror="vis.img_error(this)" alt="slots" />
+ </div>
+ <div id="slot_hover"><!-- red border around current slot --></div>
+ <div id="slot_zooming"><p>Zooming...</p></div>
+ </div>
+ <div id="slot_panright" onclick="vis.pan_right()"><!-- --></div>
+ <div id="slot_pandown" onclick="vis.pan_down()"></div>
+ {slot_legend}
+</div>
+{slot_info}
+{please_wait}
+<script type="text/javascript">
+ var slot_current_id = "{id}";
+ var show_slot_job_url = "{slot_job_url}";
+ var slot_job_index = "{job_index_param}";
+ var slot_map_info = {size: 0, width: 0, height: 0, count: 0, rows: 0, cols: 0};
+ var slot_clip_size = {slot_clip_size};
+ var oGlass = document.getElementById("slot_glass");
+ if (oGlass) {
+ oGlass.onmousedown = vis.downGlass;
+ oGlass.onmouseup = vis.upGlass;
+ oGlass.onmousemove = vis.moveGlass;
+ oGlass.onmouseout = vis.outGlass;
+ oGlass.ondblclick = clicks.doMouseDown;
+ oGlass.onclick = clicks.doMouseDown;
+ oGlass.dragging = false;
+ oGlass.down_pos = null;
+ }
+</script>
+
+[PleaseWait.javascript]
+function cancel_wait() {
+ var oGlass = document.getElementById("modal_glass");
+ var oWait = document.getElementById("please_wait");
+ if (oGlass && oGlass) {
+ oGlass.style.display = "none";
+ oWait.style.display = "none";
+ }
+ window.location.href = window.location.href;
+ return false;
+}
+function show_wait() {
+ var oGlass = document.getElementById("modal_glass");
+ var oWait = document.getElementById("please_wait");
+ if (oWait && oGlass) {
+ oGlass.style.width = document.body.offsetWidth + "px";
+ oGlass.style.height = document.body.offsetHeight + "px";
+ oGlass.style.display = "block";
+ oWait.style.visibility = "hidden";
+ oWait.style.display = "block";
+
+ promote_to_body(oGlass); // so it covers the entire page
+ promote_to_body(oWait); // so it can be centered on the page
+
+ var cp = get_center_point();
+ oWait.style.left = (cp.x - (oWait.offsetWidth / 2)) + "px";
+ oWait.style.top = (cp.y - (oWait.offsetHeight / 2)) + "px";
+ oWait.style.visibility = "visible";
+ }
+}
+function get_center_point()
+{
+ var x = 0;
+ var y = 0;
+
+ var scrollx = (document.documentElement.scrollLeft) ? document.documentElement.scrollLeft : document.body.scrollLeft;
+ var scrolly = (document.documentElement.scrollTop) ? document.documentElement.scrollTop : document.body.scrollTop;
+
+ var width = document.body.offsetWidth;
+ var height = document.body.offsetHeight;
+
+ return { x: (width + scrollx) / 2, y: (height + scrolly) / 2 };
+}
+
+
+[PleaseWait.css]
+div#modal_glass {
+ background-color: black;
+ opacity: .2;
+ -moz-opacity:.2;
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ left: 0;
+ top: 0;
+ display: none;
+ z-index: 200;
+}
+div#please_wait {
+ position: absolute;
+ display: none;
+ z-index: 201;
+ left: 100px;
+ top: 100px;
+}
+div#please_wait form.mform {
+ width: 20em;
+}
+div#please_wait form.mform div.body, div#please_wait form.mform div.foot {
+ text-align: center;
+}
+
+[PleaseWait.html]
+<div id="modal_glass" onclick="cancel_wait()"><!-- --></div>
+<div id="please_wait">
+ <form class="mform">
+ <div class="head">
+ <h1>Loading Job</h1>
+ </div>
+ <div class="body">
+ Loading Job. Please wait...
+ </div>
+ <div class="foot">
+ {cancel}
+ </div>
+ </form>
+</div>
+
+
+[SlotInfo.css]
+div.slot_info {
+ position: absolute;
+ top: 0;
+ left: 0.5em;
+ visibility: hidden;
+ z-index: 101;
+}
+
+div.slot_container {
+ position: absolute;
+ background-color: #ffffaa;
+ background-image: url(resource?name=shade.png);
+ background-position: bottom left;
+ background-repeat: repeat-x;
+ border: 1px solid #cccc99;
+ padding: 1em;
+ z-index: 101;
+}
+
+td.slot_info_title {
+ font-weight: bold;
+ height: 1.1em;
+ text-align: right;
+ padding-right: 1em;
+}
+td.slot_info_value {
+ font-weight: normal;
+ height: 1.1em;
+}
+
+html>body .outerpair1 {
+background: url(resource?name=upperrightfade.png) right top no-repeat;
+}
+
+html>body .outerpair2 {
+background: url(resource?name=lowerleftfade.png) left bottom no-repeat;
+padding-top: 8px;
+padding-left: 8px;
+}
+
+html>body .shadowbox {
+background: url(resource?name=shadow.png) bottom right;
+}
+
+html>body .innerbox {
+position: relative;
+left: -8px;
+top: -8px;
+}
+tr.hidden_row {
+ display: none;
+}
+
+[SlotInfo.html]
+<div id="{id}"><!-- place holder to receive backgound update of slot info on mouseover of a slot --></div>
+<script type="text/javascript">
+ var slot_info_url = "{slot_info_url}";
+ var slot_info_index = "{slot_info_index}";
+ var slot_info_id = "{id}";
+</script>
+
+[SlotInfo.bg_html]
+<div class="outerpair1 slot_info" id="{id}">
+<div class="outerpair2">
+<div class="shadowbox">
+<div class="innerbox slot_container">
+ <table cellspacing="0" cellpadding="0" border="0">
+ {items}
+ </table>
+</div></div></div></div>
+
+[SlotInfo.item_html]
+ <tr {row_class}><td class="slot_info_title">{title}</td>
+ <td {job_id} class="slot_info_value">{value}</td></tr>
+
+[SlotLegend.css]
+div.slot_legend {
+ margin-top: 1em;
+}
+div.slot_states, div.slot_activities {
+ float: left;
+ margin-left: 2em;
+}
+div.slot_states ul, div.slot_activities ul {
+ margin-top: 0.5em;
+ margin-left: 0.5em;
+ font-size: 0.8em;
+}
+div.slot_states ul li span {
+ font-weight: bold;
+}
+
+[SlotLegend.html]
+<div class="slot_legend">
+ {slot_states}
+ {slot_activities}
+ <div style="clear:both"><!-- --></div>
+</div>
+
+[SlotStates.html]
+ <div class="slot_states">
+ <h3>States</h3>
+ <ul>
+ {items}
+ </ul>
+ </div>
+
+[SlotActivities.html]
+ <div class="slot_activities">
+ <h3>Activities</h3>
+ <ul>
+ {items}
+ </ul>
+ </div>
+
+[SlotStates.item_html]
+ <li><span>{initial}</span> {title}</li>
+
+[SlotActivities.item_html]
+ <li><img src="{href}" width="{dot_size}" height="{dot_size}" alt="{title}"/> {title}</li>
+
\ No newline at end of file
17 years, 1 month
rhmessaging commits: r3168 - mgmt/trunk/cumin/python/cumin.
by rhmessaging-commits@lists.jboss.org
Author: eallen
Date: 2009-03-18 14:31:42 -0400 (Wed, 18 Mar 2009)
New Revision: 3168
Modified:
mgmt/trunk/cumin/python/cumin/__init__.py
mgmt/trunk/cumin/python/cumin/charts.py
mgmt/trunk/cumin/python/cumin/model.py
mgmt/trunk/cumin/python/cumin/pool.py
mgmt/trunk/cumin/python/cumin/pool.strings
mgmt/trunk/cumin/python/cumin/stat.py
mgmt/trunk/cumin/python/cumin/stat.strings
mgmt/trunk/cumin/python/cumin/system.py
mgmt/trunk/cumin/python/cumin/system.strings
Log:
Remove old slot visualization
Added new slot visualization
Modified: mgmt/trunk/cumin/python/cumin/__init__.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/__init__.py 2009-03-18 18:31:00 UTC (rev 3167)
+++ mgmt/trunk/cumin/python/cumin/__init__.py 2009-03-18 18:31:42 UTC (rev 3168)
@@ -15,7 +15,7 @@
from model import CuminModel, ModelPage, CallPage
from demo import DemoData
from page import MainPage
-from stat import StatChartPage
+from stat import StatChartPage, SlotMapPage
from action import ActionPage
from user import LoginPage, UserSession, UserSessionExpireThread
from datetime import timedelta
@@ -49,6 +49,7 @@
self.add_page(CallPage(self, "call.xml"))
self.add_page(ActionPage(self, "actions.html"))
self.add_page(StatChartPage(self, "stats.png"))
+ self.add_page(SlotMapPage(self, "slots.png"))
unprotected = set()
Modified: mgmt/trunk/cumin/python/cumin/charts.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/charts.py 2009-03-18 18:31:00 UTC (rev 3167)
+++ mgmt/trunk/cumin/python/cumin/charts.py 2009-03-18 18:31:42 UTC (rev 3168)
@@ -3,12 +3,142 @@
from cairo import *
from random import random
from time import time
+from math import sqrt, pi, ceil
from formats import *
from util import *
log = logging.getLogger("cumin.chart")
+class HeatMapChart(object):
+ def __init__(self, width=400, height=400):
+ self.width = width # final width
+ self.height = height
+ self.max_width = width # max width
+ self.max_height = height
+ self.cols = 0 # columns
+ self.rows = 0
+ self.max_size = 28 # size of each slot
+ self.min_size = 2
+ self.min_sphere_size = 8 # use boxes if below this size
+ self.min_font = 10
+ self.min_shadow = 14
+ self.surface = None
+
+ def plot_dot(self, interior, width, height):
+ pnumbx = (115 / 128.0) * width / 2.5
+ pnumby = (102 / 128.0) * width / 2.5
+ pnumbr = (14 / 128.0) * width
+ shadox = (102 / 128.0) * width
+ shadoy = (102 / 128.0) * width
+ arc = 0.5 * width
+
+ surface = ImageSurface(FORMAT_ARGB32, width, height)
+ cr = Context(surface)
+ cr.set_line_width(1)
+
+ radial = RadialGradient(pnumbx, pnumby, pnumbr, shadox, shadoy, width)
+ radial.add_color_stop_rgba(0, 1, 1, 1, 1)
+ radial.add_color_stop_rgb(1, *interior)
+ cr.set_source(radial)
+ cr.arc(arc, arc, arc, 0, 2.0 * pi)
+ cr.fill()
+ return surface
+
+ def plot_slots(self, slots, zl, zx, zy):
+ count = len(slots)
+ slot_size = self.slot_size(count, zl)
+ x = 0
+ y = 0
+ pnumbx = (115 / 128.0) * slot_size / 2.5
+ pnumby = (102 / 128.0) * slot_size / 2.5
+ pnumbr = (14 / 128.0) * slot_size
+ shadox = (102 / 128.0) * slot_size
+ shadoy = (102 / 128.0) * slot_size
+ arc = 0.5 * slot_size
+ col = 0
+ self.rows = 1
+ # the width and height depend on the number of slots
+ self.surface = ImageSurface(FORMAT_ARGB32, self.width, self.height)
+ cr = Context(self.surface)
+ cr.set_line_width(1)
+ i = 0
+ for slot in slots:
+ i = i + 1
+ interior, state = slot[:2]
+
+ #if x + slot_size >= self.width:
+ if col >= self.cols:
+ x = 0
+ y = y + slot_size
+ col = 0
+ self.rows = self.rows + 1
+
+ # draw dots if they are big enough
+ if slot_size >= self.min_sphere_size:
+ radial = RadialGradient(x + pnumbx,
+ y + pnumby,
+ pnumbr, x + shadox,
+ y + shadoy, slot_size)
+ radial.add_color_stop_rgba(0, 1, 1, 1, 1)
+ radial.add_color_stop_rgb(1, *interior)
+ cr.set_source(radial)
+ cr.arc(x + arc, y + arc, arc, 0, 2.0 * pi)
+ cr.fill()
+ else:
+ # just draw squares
+ cr.set_source_rgb(*interior)
+ cr.rectangle(x, y, slot_size - 1, slot_size - 1)
+ cr.fill()
+
+ # draw the state if the slots are big enough
+ if state and slot_size >= self.min_font:
+ #cr.set_source_rgb(interior[0]/10, interior[1]/10, interior[2]/10)
+ cr.set_source_rgb(1, 1, 1)
+ cr.select_font_face("verdana", FONT_SLANT_NORMAL, FONT_WEIGHT_BOLD)
+ cr.set_font_size(slot_size/3)
+ width, height = cr.text_extents(state[0])[2:4]
+ dx = (slot_size / 2) - (width / 2)
+ dy = (slot_size / 2) + (height / 2)
+
+ if slot_size >= self.min_sphere_size:
+ cr.set_source_rgb(*interior)
+ else:
+ cr.set_source_rgb(1,1,1)
+ cr.move_to(x + dx, y + dy)
+ cr.show_text(state[0])
+
+ x = x + slot_size
+ col = col + 1
+ return slot_size
+
+ def slot_size(self, count, zoom=1):
+ sq = sqrt(count)
+ cols = int(sq)
+ if sq > cols:
+ cols = cols + 1
+ size = int(self.width * zoom / cols)
+ if size < 2:
+ size = 2
+ if size > self.max_size * zoom:
+ size = self.max_size * zoom
+
+ #if size * cols < self.width:
+ # if size < self.max_size:
+ # size = size + 1
+
+ self.width = (size * cols) + 1
+ #if self.width < self.max_width:
+ # self.width = self.max_width
+ self.height = (ceil(count * 1.0 / cols) * size) + 1
+ #if self.height < self.max_height:
+ # self.height = self.max_height
+ self.cols = cols
+ return size
+
+ def write(self, writer):
+ self.surface.write_to_png(writer)
+
class TimeSeriesChart(object):
def __init__(self, width, height):
self.width = width - 40
Modified: mgmt/trunk/cumin/python/cumin/model.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/model.py 2009-03-18 18:31:00 UTC (rev 3167)
+++ mgmt/trunk/cumin/python/cumin/model.py 2009-03-18 18:31:42 UTC (rev 3168)
@@ -2,7 +2,7 @@
from formats import *
from job import *
from parameters import *
-from pool import PoolSlotSet, PoolMachineSet, PoolJobStats
+from pool import PoolSlotSet, PoolJobStats
from slot import SlotStatSet
from struct import unpack, calcsize
from system import SystemSlotSet
@@ -214,6 +214,7 @@
self.summary = False
self.navigable = True
self.aggregate = False
+ self.visualization = False
self.cumin_class.add_action(self)
@@ -523,6 +524,11 @@
def get_object_name(self, object):
return object.name
+ def get_visualization_action(self):
+ for action in self.actions:
+ if action.visualization:
+ return action
+
def write_event_xml(self, writer, object):
writer.write("<events errors=\"%i\" warnings=\"%i\"/>" % (0, 0))
@@ -592,75 +598,13 @@
self.itemset = None
- def get_xml_response(self, session, object, *args):
- boxes = self.get_boxes(session, object, *args)
- fields = self.get_field_tuples(session)
+ def get_boxes(self, session, object):
+ if self.itemset:
+ box_list = self.itemset.get_items(session, object)
+ return box_list
+ else:
+ return ()
- writer = Writer()
- writer.write("<%ss>" % self.itemset.name)
- for box in boxes:
- writer.write("<%s id='%s'" % (self.itemset.name, str(box["id"])))
- for field, desc in fields:
- writer.write(" %s='%s'" % (field, box[field]))
- if fields:
- extra = self.get_extra(session, box)
- for name, value in extra:
- writer.write(" %s='%s'" % (name, value))
- writer.write(" color='%s'/>" % self.get_color(session, box))
- writer.write("</%ss>" %self.itemset.name)
- return writer.to_string()
-
- def get_boxes(self, session, object, *args):
- if args:
- self.itemset.set_args(session, *args)
- box_list = self.itemset.get_items(session, object)
- return box_list
-
- def get_color(self, session, box):
- return ""
-
- def get_extra(self, session, box):
- return list()
-
- def get_colors(self):
- return list()
-
-class SlotVisualization(Visualization):
- # list of status/colors in the order we want them displayed
- # in the legend
- load_colors = [("Idle", "clear"),
- ("Busy", "green"),
- ("Suspended", "red"),
- ("Vacating", "orange"),
- ("Killing", "blue"),
- ("Benchmarking", "yellow"),
- ("Unknown", "grey")]
-
- load_states = [("Unclaimed", "Unclaimed"),
- ("Claimed", "Claimed"),
- ("Owner", "Owner"),
- ("Matched", "Matched"),
- ("Preempting", "Preempting")]
-
- def get_field_tuples(self, session):
- return [("name", "Name"), ("machine", "Machine"), ("job_id", "Job"), ("state", "State"), ("activity", "Activity")]
-
- def get_extra(self, session, slot):
- return [("jid", slot["jid"])]
-
- def get_color(self, session, slot):
- activity = slot["activity"]
- for status, color in self.load_colors:
- if status == activity:
- return color
- return "grey"
-
- def get_colors(self):
- return self.load_colors
-
- def get_states(self):
- return self.load_states
-
class CuminSystem(RemoteClass):
def __init__(self, model):
super(CuminSystem, self).__init__(model, "system", Sysimage, SysimageStats)
@@ -712,6 +656,7 @@
action = self.SystemSlotVisualization(self, "slots")
action.navigable = False
+ action.visualization = True
#action = CuminAction(self, "ping")
#action.title = "Send Ping"
@@ -735,7 +680,7 @@
text = value and "%0.2f" % value or ""
return text
- class SystemSlotVisualization(SlotVisualization):
+ class SystemSlotVisualization(Visualization):
def __init__(self, cls, name):
super(CuminSystem.SystemSlotVisualization, self).__init__(cls, name)
@@ -1998,10 +1943,8 @@
action = self.PoolSlotVisualization(self, "slots")
action.navigable = False
+ action.visualization = True
- action = self.VisMachine(self, "machines")
- action.navigable = False
-
action = self.SeeAllPools(self, "allpools")
action.summary = True
@@ -2077,34 +2020,14 @@
return total and "%2.2f" % percent or "-"
return ""
- class PoolSlotVisualization(SlotVisualization):
+ class PoolSlotVisualization(Visualization):
def __init__(self, cls, name):
super(CuminPool.PoolSlotVisualization, self).__init__(cls, name)
self.itemset = self.ModelPoolSlotSet(cls.model.app, "slot")
self.itemset.items.path = "CuminPool.PoolSlotVisualization.slot"
- def set_machine(self, session, machine):
- self.itemset.set_machine(session, machine)
-
- def get_machine(self, session):
- return self.itemset.get_machine(session)
-
class ModelPoolSlotSet(PoolSlotSet):
- def __init__(self, app, name):
- super(CuminPool.PoolSlotVisualization.ModelPoolSlotSet, self).__init__(app, name)
-
- self.__machine = None
-
- def set_args(self, session, machine):
- self.set_machine(session, machine)
-
- def set_machine(self, session, machine):
- self.__machine= machine
-
- def get_machine(self, session):
- return self.__machine
-
def render_sql_where(self, session, pool):
elems = list()
elems.append("s.pool = %(pool)s")
@@ -2112,16 +2035,10 @@
if recent:
elems.append(recent)
- if self.__machine:
- elems.append("machine = %(machine)s")
-
return "where %s" % " and ".join(elems)
def get_sql_values(self, session, pool):
values = {"pool": pool.id}
- machine = self.__machine
- if machine:
- values["machine"] = machine
return values
def render_sql_limit(self, session, *args):
@@ -2169,36 +2086,6 @@
values = {"pool": pool.id}
return values
- class VisMachine(Visualization):
- load_colors = [("Idle", "clear"),
- ("> 0%", "green"),
- ("> 25%", "yellow"),
- ("> 50%", "blue"),
- ("> 75%", "green3")]
-
- def __init__(self, cls, name):
- super(CuminPool.VisMachine, self).__init__(cls, name)
-
- self.itemset = PoolMachineSet(cls.model.app, "machine")
- self.itemset.items.path = "CuminPool.VisMachine.machine"
-
- def get_field_tuples(self, session):
- return [("machine", "Machine"), ("busy", "Busy Slots"), ("idle", "Idle Slots")]
-
- def get_color(self, session, machine):
- total = float(machine["total"])
- busy = float(machine["busy"])
- work = total > 0.0 and busy / total or 0.0
-
- percents = [0.0, 0.25, 0.5, 0.75, 1.0]
- for i in range(len(percents)):
- if work <= percents[i]:
- return self.load_colors[i][1]
- return "grey"
-
- def get_colors(self):
- return self.load_colors
-
class CuminLimit(CuminClass):
def __init__(self, model):
super(CuminLimit, self).__init__ \
@@ -2326,9 +2213,6 @@
prop.description = "The submitter of the job"
prop.writable = False
- prop = AdProperty(self, "BufferBlockSize")
- prop.example = "32768"
-
### Condor Info Group
prop = AdProperty(self, "CondorVersion")
prop.group = "Condor Info"
@@ -2388,6 +2272,10 @@
prop.writable = False
######## Other
+ prop = AdProperty(self, "BufferBlockSize")
+ prop.example = "32768"
+ prop.group = "Other"
+
prop = AdProperty(self, "ClusterId")
prop.description = "The id of the cluster the job belongs to"
prop.group = "Other"
Modified: mgmt/trunk/cumin/python/cumin/pool.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/pool.py 2009-03-18 18:31:00 UTC (rev 3167)
+++ mgmt/trunk/cumin/python/cumin/pool.py 2009-03-18 18:31:42 UTC (rev 3168)
@@ -18,6 +18,7 @@
from negotiator import NegotiatorSet, NegotiatorFrame, NegStart, NegStop
from limits import LimitsSet, LimitsFrame
from slot import SlotSet, MachineSet, SlotStatSet
+from visualizations import SlotMap
strings = StringCatalog(__file__)
log = logging.getLogger("cumin.pool")
@@ -134,6 +135,10 @@
self.job_group_remove = JobGroupRemove(app, "jobgroupremove")
self.add_mode(self.job_group_remove)
+ def show_job_frame(self, session):
+ self.page.set_current_frame(session, self.job)
+ return self.show_mode(session, self.job)
+
def show_negs_start(self, session):
self.page.set_current_frame(session, self.__startneg)
return self.show_mode(session, self.__startneg)
@@ -171,8 +176,8 @@
stats = PoolStats(app, "stats")
self.__tabs.add_tab(stats)
- jobs = JobsAndGroupsTab(app, "jobs")
- self.__tabs.add_tab(jobs)
+ self.jobs = JobsAndGroupsTab(app, "jobs")
+ self.__tabs.add_tab(self.jobs)
self.scheds = PoolSchedulerSet(app, "scheds")
self.__tabs.add_tab(self.scheds)
@@ -284,25 +289,6 @@
def filter(self, session, system, slots):
return slots
-class PoolMachineSet(MachineSet):
- def get_args(self, session):
- return self.frame.get_args(session)
-
- def render_sql_where(self, session, pool):
- elems = list()
- elems.append("s.pool = %(pool)s")
- recent = self.get_recent_sql_where(session)
- if recent:
- elems.append(recent)
-
- return "where %s" % " and ".join(elems)
-
- def get_sql_values(self, session, pool):
- return {"pool": pool.id}
-
- def render_sql_orderby(self, session, pool):
- return "order by id asc"
-
class PoolStats(Widget):
def __init__(self, app, name):
super(PoolStats, self).__init__(app, name)
@@ -310,187 +296,19 @@
stats = PoolStatSet(app, "general", "general")
self.add_child(stats)
- self.machine_grid = self.MachineVisualization(app, "machine_grid")
- self.add_child(self.machine_grid)
-
- self.slot_grid = self.SlotVisualization(app, "slot_grid")
- self.add_child(self.slot_grid)
-
- self.all_fits = Attribute(app, "can_show_all")
- self.add_attribute(self.all_fits)
+ self.slot_map = self.PoolSlotMap(app, "pool_slot_map")
+ self.add_child(self.slot_map)
- self.machine_param = Parameter(app, "machine_param")
- self.add_parameter(self.machine_param)
-
- def process(self, session):
- super(PoolStats, self).process(session)
- all_slots = self.slot_grid.show_all_slots.get(session)
- machine = self.machine_param.get(session)
- all_fits = True
-
- if all_slots == "a":
- machine = None
-
- if not machine:
- self.slot_grid.set_machine(session, None)
- all_fits = self.slot_grid.will_it_fit(session)
- if not all_fits:
- machine = self.machine_grid.get_1st_machine(session)
- else:
- machine = ""
-
- self.all_fits.set(session, all_fits)
- self.slot_grid.set_machine(session, machine)
-
def render_title(self, session):
return "Statistics"
- def render_machine_title(self, session):
- slots_fit = self.all_fits.get(session)
- if not slots_fit:
- pool = self.frame.get_args(session)[0]
- return "Machines on %s" % pool.name
-
- def render_machine_help(self, session):
- slots_fit = self.all_fits.get(session)
- if not slots_fit:
- return "Select a Machine to view its slots"
-
- def render_slot_job_url(self, session):
- job = Identifiable("XXX")
- return self.page.main.pool.job.get_href(session, job)
-
- class SlotVisualization(StatUtilizationGrid):
- def __init__(self, app, name):
- super(PoolStats.SlotVisualization, self).__init__(app, name)
-
- self.show_all_slots = self.ShowAllSlots(app, "show_all_slots")
- self.add_child(self.show_all_slots)
-
- def render(self, session, *args):
- slots_fit = self.parent.all_fits.get(session)
- if slots_fit:
- return super(PoolStats.SlotVisualization, self).render(session, *args)
-
- def get_cells(self, session):
- pool = self.frame.get_args(session)[0]
- action = self.app.model.pool.slots
- return action.get_boxes(session, pool)
+ class PoolSlotMap(SlotMap):
+ def get_title_name(self, session, pool):
+ return pool.name
- def render_title(self, session):
- pool = self.frame.get_args(session)[0]
- machine = self.get_machine(session)
- return machine and "Slots on (%s)" % machine or "Slots on %s" % pool.name
-
- def set_machine(self, session, machine):
- action = self.app.model.pool.slots
- action.set_machine(session, machine)
-
- def get_machine(self, session):
- action = self.app.model.pool.slots
- return action.get_machine(session)
-
- def get_colors(self, session):
- action = self.app.model.pool.slots
- return action.get_colors()
-
- def get_states(self, session):
- action = self.app.model.pool.slots
- return action.get_states()
-
- def get_color(self, session, job):
- action = self.app.model.pool.slots
- return action.get_color(session, job)
+ def render_slot_clip_size(self, session, *args):
+ return 400
- def get_contents(self, session, slot):
- return ""
-
- def get_href(self, session, slot):
- return "#"
-
- def get_url(self, session):
- pool = self.parent.frame.get_args(session)[0]
- machine = self.get_machine(session)
- return "call.xml?class=pool;id=%s;method=slots;xargs=%s" % (pool.id, machine)
-
- def get_sticky_info(self, session):
- action = self.app.model.pool.slots
- return action.get_field_tuples(session)
-
- class ShowAllSlots(StateSwitch):
- def __init__(self, app, name):
- super(PoolStats.SlotVisualization.ShowAllSlots, self).__init__(app, name)
-
- self.add_state("a", "All")
- self.add_state("m", "Machine")
-
- def render(self, session):
- state = self.get(session)
- if state == "m":
- return super(PoolStats.SlotVisualization.ShowAllSlots, self).render(session)
-
- def render_href(self, session):
- state = self.get(session)
- if state == "m":
- branch = session.branch()
- self.set(branch, "a")
- return branch.marshal()
- else:
- return "#"
-
- def render_class(self, session):
- state = self.get(session)
- return state == "a" and "disabled" or "enabled"
-
- class MachineVisualization(StatUtilizationGrid):
- def render(self, session, *args):
- slots_fit = self.parent.all_fits.get(session)
- if not slots_fit:
- return super(PoolStats.MachineVisualization, self).render(session, *args)
-
- def get_cells(self, session):
- pool = self.frame.get_args(session)[0]
- action = self.app.model.pool.machines
- return action.get_boxes(session, pool)
-
- def render_title(self, session):
- return "Machines"
-
- def render_vis_help(self, session):
- return "Click on a machine to view its slots"
-
- def get_1st_machine(self, session):
- pool = self.frame.get_args(session)[0]
- action = self.app.model.pool.machines
- boxes = action.get_boxes(session, pool)
- return boxes[0]["machine"]
-
- def get_colors(self, session):
- action = self.app.model.pool.machines
- return action.get_colors()
-
- def get_color(self, session, machine):
- action = self.app.model.pool.machines
- return action.get_color(session, machine)
-
- def get_contents(self, session, machine):
- return ""
-
- def get_href(self, session, data):
- machine = data["machine"]
- branch = session.branch()
- self.parent.machine_param.set(branch, machine)
- self.parent.slot_grid.show_all_slots.set(branch, "m")
- return branch.marshal()
-
- def get_url(self, session):
- pool = self.parent.frame.get_args(session)[0]
- return "call.xml?class=pool;id=%s;method=machines" % pool.id
-
- def get_sticky_info(self, session):
- action = self.app.model.pool.machines
- return action.get_field_tuples(session)
-
class PoolStatSet(StatSet):
def render_rate_text(self, session, args):
return "Percentage"
@@ -518,12 +336,24 @@
return values
class PoolStatus(CuminStatus):
+ def __init__(self, app, name):
+ super(PoolStatus, self).__init__(app, name)
+
+ self.item_tmpl = Template(self, "status_html")
+
def render_title(self, session, pool):
return "Pool Status"
def render_status(self, session, pool):
action = self.app.model.pool.poolstatus
record = action.get_stat_record(session, pool)
+ if record and ("idl" in record) and ("all" in record):
+ writer = Writer()
+ self.item_tmpl.render(writer, session, record)
+ return writer.to_string()
- return record and "<div><span>%i</span> of <span>%i</span> slots idle</div>" % \
- (record["idl"], record["all"]) or ""
+ def render_idle(self, session, record):
+ return record["idl"]
+
+ def render_total(self, session, record):
+ return record["all"]
Modified: mgmt/trunk/cumin/python/cumin/pool.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/pool.strings 2009-03-18 18:31:00 UTC (rev 3167)
+++ mgmt/trunk/cumin/python/cumin/pool.strings 2009-03-18 18:31:42 UTC (rev 3168)
@@ -75,99 +75,26 @@
{status}
</div>
<script type="text/javascript">
-<![CDATA[
+//<![CDATA[
cumin.objectListeners["{id}"] = updatePoolStatus;
-]]>
+//]]>
</script>
-[PoolStats.css]
-div.vistats {
- margin-bottom: 2em;
-}
-div.vistats ul.radiotabs {
- margin: 1em 0 0 1em;
-}
-.machine_help {
- color: #444;
- font-size: 0.8em;
-}
+[PoolStatus.status_html]
+ <div>
+ <span>{idle}</span> of <span>{total}</span> slots idle
+ </div>
-div#legend_slot_grid { float: left; margin-right: 1.5em;}
-div#legend_slot_grid h2, div#legend1_slot_grid h2 { margin-bottom: 1em;}
-div#legend1_slot_grid .btn.Unclaimed,
-div#legend1_slot_grid .btn.Claimed,
-div#legend1_slot_grid .btn.Matched,
-div#legend1_slot_grid .btn.Owner,
-div#legend1_slot_grid .btn.Preempting { width:28px; height:28px; margin-bottom:1px;}
-
[PoolStats.html]
-<div style="width: 50%; float: left;">
+<div style="width: 40%; float: left;">
<h2>General</h2>
<div>
{general}
</div>
</div>
<div style="float: left; margin-left: 4em;">
- {machine_grid}
- {slot_grid}
+ {pool_slot_map}
</div>
<div style="clear:left;"><!-- --></div>
-<script type="text/javascript">
-var show_slot_job_url = "{slot_job_url}";
-</script>
-[SlotVisualization.html]
-{show_all_slots}
-<div class="vistats">
- <h2>{title}</h2>
- <div class="StatUtilizationGrid" id="{id}">
- <div class="visualization">
- <div id="StatGrid" class="StatGrid" style="width:{grid_width};">
- {grid}
- <div style="clear:left;"><!-- --></div>
- </div>
- </div>
- <div id="legend_{name}" class="cell_legend">
- <h2>Activities</h2>
- {grid_legend}
- </div>
- <div id="legend1_{name}" class="cell_legend">
- <h2>States</h2>
- {grid_legend1}
- </div>
- </div>
-</div>
-{grid_updater}
-
-[ShowAllSlots.html]
- <div style="margin:1em;">
- <a href="{href}"><button class="{class}" type="button" tabindex="100" >Show All Machines</button></a>
- </div>
-
-[MachineVisualization.javascript]
-function got_machine_grid(obj, id) {
- for (var cell in obj.machines.machine) {
- var machine = obj.machines.machine[cell]
- var o_Button = document.getElementById("button_"+cell);
- if (o_Button) {
- o_Button.className = "btn "+machine.color;
- o_Button.onmouseover = over_cell;
- o_Button.onmouseout = out_cell
- }
- var o_Machine = document.getElementById("cell_machine_"+cell);
- if (o_Machine) {
- o_Machine.innerHTML = machine.machine;
- }
- var o_Busy = document.getElementById("cell_busy_"+cell);
- if (o_Busy) {
- o_Busy.innerHTML = machine.busy;
- }
- var o_Idle = document.getElementById("cell_idle_"+cell);
- if (o_Idle) {
- o_Idle.innerHTML = machine.idle;
- }
- }
- setTimeout("get_machine_grid()", 1000);
-}
-
Modified: mgmt/trunk/cumin/python/cumin/stat.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/stat.py 2009-03-18 18:31:00 UTC (rev 3167)
+++ mgmt/trunk/cumin/python/cumin/stat.py 2009-03-18 18:31:42 UTC (rev 3168)
@@ -2,11 +2,14 @@
from wooly.widgets import *
from mint import *
from math import sqrt
+from random import randint
from widgets import *
from parameters import *
from util import *
from formats import *
+import tempfile
+from datetime import timedelta, datetime
strings = StringCatalog(__file__)
@@ -140,208 +143,149 @@
def render_stat_name(self, session, stat, object):
return stat.name
-class StatUtilizationGrid(Widget):
- def __init__(self, app, name):
- super(StatUtilizationGrid, self).__init__(app, name)
-
- self.cells = self.GridCells(app, "grid")
- self.add_child(self.cells)
+class ImageCache(object):
+ def __init__(self):
+ self.__files = dict() # {name: {"time": time_created, "file": file object, "cookie": (cookie values)}}
- legend = self.Legend(app, "grid_legend")
- legend.get_method = self.get_colors
- self.add_child(legend)
-
- legend1 = self.Legend(app, "grid_legend1")
- legend1.get_method = self.get_states
- self.add_child(legend1)
-
- ajax = self.Updater(app, "grid_updater")
- self.add_child(ajax)
-
- self.max_px = 480.0
- self.max_item_px = 28.0
- self.max_columns = 20.0
- self.max_background_cols = 15 # max columns with background image
+ def find_recent(self, name, max_age):
+ for cname in self.__files:
+ if cname == name:
+ age = timedelta(seconds=max_age)
+ now = datetime.now()
+ then = self.__files[cname]["time"]
+ if now - then < age:
+ file = self.__files[cname]["file"]
+ file.seek(0)
+ return (file.read(), self.__files[cname]["cookie"])
+ else:
+ break
- def render_title(self, session):
- return "Utilization"
+ return (None, None)
- def render_name(self, session):
- return self.name
-
- def render_vis_help(self, session):
- pass
-
- def will_it_fit(self, session):
- count = len(self.cells.get_items(session))
- columns = self.cells.calculate_columns(count)
- return columns <= self.max_columns
-
- def get_cell_class(self, session):
- count = len(self.cells.get_items(session))
- columns = self.cells.calculate_columns(count)
- return columns > self.max_background_cols and "small" or "big"
-
- def get_grid_width(self, session):
- count = len(self.cells.get_items(session))
- columns = self.cells.calculate_columns(count)
- # we have approx 480px to work with
- width = float(columns) * self.max_item_px
- if width > self.max_px:
- width = self.max_px
- extra = 3.0 * columns # left right border plus 1 right margin
- if columns > self.max_background_cols:
- extra = 0
- return int(width + extra)
-
- def render_grid_width(self, session):
- width = self.get_grid_width(session) or self.max_px
- return "%ipx" % int(width)
+ def create_cache_file(self, name, args):
+ if name not in self.__files:
+ file = tempfile.TemporaryFile()
+ else:
+ file = self.__files[name]["file"]
+ file.seek(0)
+ file.truncate()
- class GridCells(ItemSet):
- def __init__(self, app, name):
- super(StatUtilizationGrid.GridCells, self).__init__(app, name)
-
- self.width = Attribute(app, "width")
- self.add_attribute(self.width)
+ self.__files[name] = {"time": datetime.now(), "file": file, "cookie": args}
+ return file
- self.sticky = self.Sticky(app, "sticky_info")
- self.add_child(self.sticky)
+class SlotMapPage(Page):
+ interiors = {"Idle": (.7,.7,.7),
+ "Busy": (0.0, 0.4, 0.0),
+ "Suspended": (1,0,0),
+ "Vacating": (1,.73,.367),
+ "Killing": (0,0,1),
+ "Benchmarking": (1,.8,.8),
+ None: (.8,.8,.8)}
+
+ max_width = 400
+ max_png_age = 30
+ def __init__(self, app, name):
+ super(SlotMapPage, self).__init__(app, name)
- def render(self, session, *args):
- count = len(self.get_items(session))
- if count == 0:
- return "0 slots found"
- else:
- return super(StatUtilizationGrid.GridCells, self).render(session, *args)
+ self.class_ = CuminClassParameter(app, "class")
+ self.add_parameter(self.class_)
- def do_get_items(self, session):
- cells = self.parent.get_cells(session)
- self.width.set(session,
- self.calculate_cell_width(len(cells)))
- return cells
-
- def render_cell_id(self, session, cell):
- return cell["id"]
+ self.id = IntegerParameter(app, "id")
+ self.add_parameter(self.id)
- def render_cell_width(self, session, cell):
- return self.width.get(session)
+ self.zoom_level = IntegerParameter(app, "zl")
+ self.add_parameter(self.zoom_level)
- def render_cell_class(self, session, cell):
- return self.parent.get_cell_class(session)
-
- def calculate_columns(self, count):
- sq = sqrt(count)
- isq = int(sq)
- if sq > isq:
- isq = isq + 1
- return isq
-
- def calculate_cell_width(self, count):
- columns = self.calculate_columns(count)
- width = self.parent.max_item_px
- if columns:
- min = self.parent.max_px / float(columns)
- width = min > self.parent.max_item_px and self.parent.max_item_px or min
- return "%ipx" % int(width)
+ self.zoom_x = IntegerParameter(app, "zx")
+ self.add_parameter(self.zoom_x)
- def render_href(self, session, cell):
- return self.parent.get_href(session, cell)
-
- def render_color(self, session, cell):
- return self.parent.get_color(session, cell)
-
- def render_contents(self, session, cell):
- return self.parent.get_contents(session, cell)
-
- def get_sticky_info(self, session):
- return self.parent.get_sticky_info(session)
+ self.zoom_y = IntegerParameter(app, "zy")
+ self.add_parameter(self.zoom_y)
- def render_sticky_rows(self, session, cell):
- return self.sticky.render_items(session, cell)
-
- class Sticky(ItemSet):
- def do_get_items(self, session, cell):
- info = self.parent.get_sticky_info(session)
- return [(inf, cell["id"]) for inf in info]
-
- def render_sticky_name(self, session, item):
- return item[0][0]
-
- def render_sticky_title(self, session, item):
- return item[0][1]
-
- def render_sticky_object_id(self, session, item):
- return item[1]
+ self.dot = Parameter(app, "dot")
+ self.add_parameter(self.dot)
+
+ self.cache = ImageCache()
- def get_cells(self, session):
- """ should return a list of dictionaries """
- return list()
-
- def get_href(self, session, cell):
- return "#"
+ def get_content_type(self, session):
+ return "image/png"
- def get_color(self, session, cell):
- return "clear"
-
- def get_contents(self, session, cell):
- return ""
+ def get_cache_control(self, session):
+ return "no-cache"
- def get_colors(self, session):
- return ["clear"]
+ def get_args(self, session):
+ cls = self.class_.get(session)
+ if cls:
+ id = self.id.get(session)
+ return (cls.mint_class.get(id),)
+ else:
+ return (None,)
+
+ def render_dot(self, session, dot):
+ map = HeatMapChart()
+ if dot == "Unknown":
+ dot = None
+ surface = map.plot_dot(self.interiors[dot], 12, 12)
+ writer = Writer()
+ surface.write_to_png(writer)
+ return writer.to_string()
- def get_states(self, session):
- return ["Unclaimed"]
-
- def get_url(self, session):
- """ returns something like
- "call.xml?class=system;id=%i;method=slots" % system.id
- """
- pass
+ def do_render(self, session, object):
+ dot = self.dot.get(session)
+ if dot:
+ return self.render_dot(session, dot)
- def get_sticky_info(self, session):
- return [("Name", "Display Title")]
-
- def get_fn(self, session):
- return self.name
-
- def got_fn(self, session):
- return self.name
-
- def elem_id(self, session):
- return self.name
+ zl = self.zoom_level.get(session)
+ zx = self.zoom_x.get(session)
+ zy = self.zoom_y.get(session)
- class Legend(ItemSet):
- def render(self, session, *args):
- if len(self.parent.cells.get_items(session)) > 0:
- return super(StatUtilizationGrid.Legend, self).render(session, *args)
-
- def do_get_items(self, session, *args):
- return self.get_method(session)
-
- def render_legend_text(self, session, color):
- return color[0]
+ # determine if cached copy is recent enough
+ cached_png, args = self.get_cached(session, zl)
+ if cached_png:
+ #print "returning cached copy of png at zoom %i, x %i, y %i" % (zl, zx, zy)
+ self.set_cookie(session, args)
+ return cached_png
- def render_legend_color(self, session, color):
- return color[1]
-
- class Updater(AjaxField):
- def do_render(self, session):
- return self.render_script(session)
+ #print "starting rendering png at zoom %i, x %i, y %i" % (zl, zx, zy)
+ map = HeatMapChart(self.max_width, self.max_width)
- def get_url(self, session):
- return self.parent.get_url(session)
+ cls = self.class_.get(session)
+ action = cls.get_visualization_action()
+ slot_info = action.get_boxes(session, object)
+
+ if len(slot_info) == 0:
+ return ""
+
+ slots = [ [self.interiors[x["activity"]], x["state"]] for x in slot_info ]
+ size = map.plot_slots(slots, zl, zx, zy)
- def get_fn(self, session):
- return self.parent.get_fn(session)
+ args = (size, map.width, map.height, len(slots), map.rows, map.cols)
+ self.set_cookie(session, args)
+ self.cache_it(session, zl, map, args)
- def got_fn(self, session):
- return self.parent.got_fn(session)
+ writer = Writer()
+ map.write(writer)
+ #print "done rendering png at zoom %i, x %i, y %i" % (zl, zx, zy)
+ return writer.to_string()
+
+ def get_cached(self, session, zl):
+ filename = self.__gen_filename(session, zl)
+ return self.cache.find_recent(filename, self.max_png_age)
- def elem_id(self, session):
- return self.parent.elem_id(session)
+ def cache_it(self, session, zl, map, args):
+ filename = self.__gen_filename(session, zl)
+ writer = self.cache.create_cache_file(filename, args)
+ map.write(writer)
+
+ def __gen_filename(self, session, zl):
+ cls = self.class_.get(session)
+ id = self.id.get(session)
+ return "-".join((cls.cumin_name, str(id), str(zl)))
-
+ def set_cookie(self, session, args):
+ cookie = "|".join((str(x) for x in args))
+ session.set_cookie("slot_info", cookie)
+
class StatChartPage(Page):
def __init__(self, app, name):
super(StatChartPage, self).__init__(app, name)
Modified: mgmt/trunk/cumin/python/cumin/stat.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/stat.strings 2009-03-18 18:31:00 UTC (rev 3167)
+++ mgmt/trunk/cumin/python/cumin/stat.strings 2009-03-18 18:31:42 UTC (rev 3168)
@@ -45,7 +45,7 @@
table.StatSet {
width: 100%;
border-collapse: collapse;
- margin: 1em 0.5em;
+ margin: 1em 0;
}
table.StatSet tr {
@@ -105,15 +105,8 @@
var img = chart.elem("img")
var src = img.getattr("src");
- var sep = src.lastIndexOf(";");
- var time = new Date().getTime();
+ src = refreshTime(src);
- if (isNaN(parseInt(src.substring(sep + 1)))) {
- src = src + ";" + time;
- } else {
- src = src.substring(0, sep) + ";" + time;
- }
-
img.setattr("src", src);
/*
@@ -127,7 +120,18 @@
}
*/
}
+function refreshTime(src) {
+ var sep = src.lastIndexOf(";");
+ var time = new Date().getTime();
+ if (isNaN(parseInt(src.substring(sep + 1)))) {
+ src = src + ";" + time;
+ } else {
+ src = src.substring(0, sep) + ";" + time;
+ }
+ return src;
+}
+
[StatValueChart.css]
div.StatValueChart {
font-size: 0.9em;
@@ -165,179 +169,3 @@
<span class="ph" statname="{stat_name}" statmode="{mode}">{stat_value}</span>
</li>
-[StatUtilizationGrid.javascript]
-function over_cell() {
- this.get_left = function (o) {
- var p = o.offsetParent;
- var true_left = o.offsetLeft;
-
- while (p != null) {
- var tag = p.tagName;
- if (p.clientLeft) {
- if ( (tag != "TABLE") && (tag != "BODY") ) {
- true_left += p.clientLeft;
- }
- }
- true_left += p.offsetLeft;
- p = p.offsetParent;
- }
- return true_left;
- }
-
- var id = this.id;
- var onote = document.getElementById("note_"+id);
- if (onote) {
- if (document.all) {
- this.title = onote.innerText;
- } else {
- onote.style.visibility = "hidden";
- onote.style.display = "block";
- if (onote.style.left.indexOf("px") == -1) {
- var left = this.get_left(onote);
- var right = left + onote.offsetWidth;
- if (window.innerWidth) {
- wwidth = window.innerWidth;
- if (right > wwidth) {
- oparent = onote.offsetParent;
- pleft = this.get_left(oparent);
- onote.style.left = "-" + (onote.offsetWidth - (wwidth - pleft) + 4) + "px";
- } else {
- onote.style.left = "50%";
- }
- }
- }
- onote.style.visibility = "visible";
- }
- }
-}
-function out_cell() {
- var id = this.id;
- var onote = document.getElementById("note_"+id);
- if (onote) {
- onote.style.display = "none";
- }
-}
-
-[StatUtilizationGrid.css]
-div.StatGrid a {
- float:left;
- border:1px solid #EAEAEA;
- margin: 0 1px 1px 0;
- position: relative;
- color: black;
-}
-div.StatGrid a.small {
- float:left;
- position: relative;
- color: black;
-}
-div.StatGrid a.small:hover { border: 0px; }
-
-div.StatGrid a:hover { border: 1px solid #a00; }
-.btn.yellow { background: #ffc; }
-.btn.green { background: #cfc; }
-.btn.blue { background: #ccf; }
-.btn.red { background: #fcc; }
-.btn.orange { background: #ffbb5e; }
-.btn.black { background: #444; }
-.btn.grey { background: #ccc; }
-.btn.clear { background: white; }
-.btn.green1 { background: #9f9; }
-.btn.green2 { background: #6c6; }
-.btn.green3 { background: #393; }
-
-.btn[class] { background-position: bottom; }
-.btn.Claimed { background-image: url(resource?name=claimed1.png); }
-.btn.Unclaimed { background-image: url(resource?name=shade1.png); }
-.btn.Matched { background-image: url(resource?name=match.png); }
-.btn.Owner { background-image: url(resource?name=pwn.png); }
-.btn.Preempting { background-image: url(resource?name=preempt.png); }
-
-div.visualization {
- padding-right: 2em;
-}
-
-div.StatUtilizationGrid {
- margin-top: 1em;
- margin-left: 1em;
-}
-
-div.sticky_note {
- display: none;
- font-size: 0.8em;
- position: absolute;
- top: 120%;
- left: 50%;
- padding: 1em;
- background-color: #ffffaa;
- background-image: url(resource?name=shade.png);
- background-position: bottom right;
- background-repeat: repeat-x;
- border: 1px solid #cccc99;
- z-index: 1;
-}
-
-table.sticky_table {
- border-collapse: collapse;
-}
-td.sticky_names {
- font-weight: bold;
- line-height: 1em;
-}
-td.sticky_values {
- line-height: 1em;
-}
-div.cell_legend {
- margin: 1em 0;
- font-size: 0.8em;
- color: #000;
- position: relative;
-}
-div.cell_legend button {
- position: relative;
- top: -2px;
-}
-
-[StatUtilizationGrid.html]
-<div class="vistats">
- <h2>{title}</h2>
- <div class="vis_help">{vis_help}</div>
- <div class="StatUtilizationGrid" id="{id}">
- <div class="visualization">
- <div id="StatGrid" class="StatGrid" style="width:{grid_width};">
- {grid}
- <div style="clear:left;"><!-- --></div>
- </div>
- </div>
- <div id="legend_{name}" class="cell_legend">
- {grid_legend}
- </div>
- </div>
-</div>
-{grid_updater}
-
-[GridCells.html]
-{items}
-
-[GridCells.item_html]
- <a class="{cell_class}" href="{href}">
- <div id="button_{cell_id}" class="btn {color}" style="width:{cell_width}; height:{cell_width};">
- {contents}
- </div>
- <div id="note_button_{cell_id}" class="sticky_note">
- <table class="sticky_table">
- {sticky_rows}
- </table>
- </div>
- </a>
-
-[Sticky.item_html]
-<tr>
- <td class="sticky_names" nowrap="nowrap">{sticky_title}: </td>
- <td class="sticky_values" nowrap="nowrap"><span id="cell_{sticky_name}_{sticky_object_id}"></span></td>
-</tr>
-
-[Legend.item_html]
-<li>
- <button class="btn {legend_color}" ></button> {legend_text}
-</li>
Modified: mgmt/trunk/cumin/python/cumin/system.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/system.py 2009-03-18 18:31:00 UTC (rev 3167)
+++ mgmt/trunk/cumin/python/cumin/system.py 2009-03-18 18:31:42 UTC (rev 3168)
@@ -7,6 +7,7 @@
from parameters import *
from formats import *
from util import *
+from visualizations import SlotMap
strings = StringCatalog(__file__)
@@ -130,9 +131,6 @@
def __init__(self, app, name):
super(SystemStats, self).__init__(app, name)
- self.grid = self.SlotUtilizationGrid(app, "slot_grid")
- self.add_child(self.grid)
-
self.add_child(StatSet(app, "stats", "general"))
chart = StatValueChart(app, "freemem")
@@ -143,6 +141,9 @@
chart.stats = ("loadAverage1Min",)
self.add_child(chart)
+ vis = self.SystemSlotMap(app, "system_slot_map")
+ self.add_child(vis)
+
def render_title(self, session):
return "Statistics"
@@ -150,47 +151,13 @@
job = Identifiable("XXX")
return self.page.main.pool.job.get_href(session, job)
- class SlotUtilizationGrid(StatUtilizationGrid):
- def render(self, session):
- cells = self.get_cells(session)
- if len(cells) > 0:
- return super(SystemStats.SlotUtilizationGrid, self).render(session)
+ class SystemSlotMap(SlotMap):
+ def get_title_name(self, session, sysimage):
+ return sysimage.nodeName
- def get_cells(self, session):
- system = self.frame.get_args(session)[0]
- action = self.app.model.system.slots
- return action.get_boxes(session, system)
+ def render_slot_clip_size(self, session, *args):
+ return 120
- def render_title(self, session):
- return "Slot Utilization"
-
- def get_colors(self, session):
- action = self.app.model.system.slots
- return action.get_colors()
-
- def get_color(self, session, slot):
- action = self.app.model.system.slots
- return action.get_color(session, slot)
-
- def get_contents(self, session, slot):
- return ""
-
- def get_href(self, session, slot):
- branch = session.branch()
- try:
- job = Job.select("custom_id = '%s'" % slot.JobId)[0]
- except Exception, e:
- return "#"
- return self.page.main.pool.job.get_href(branch, job)
-
- def get_url(self, session):
- system = self.parent.frame.get_args(session)[0]
- return "call.xml?class=system;id=%i;method=slots" % system.id
-
- def get_sticky_info(self, session):
- action = self.app.model.system.slots
- return action.get_field_tuples(session)
-
class SystemView(CuminView):
def __init__(self, app, name):
super(SystemView, self).__init__(app, name)
Modified: mgmt/trunk/cumin/python/cumin/system.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/system.strings 2009-03-18 18:31:00 UTC (rev 3167)
+++ mgmt/trunk/cumin/python/cumin/system.strings 2009-03-18 18:31:42 UTC (rev 3168)
@@ -46,53 +46,6 @@
[TopSystemSet.count_sql]
--
-[SlotUtilizationGrid.javascript]
-function got_slot_grid(obj, id) {
- for (var cell in obj.slots.slot) {
- var slot = obj.slots.slot[cell]
- var oslot_Button = document.getElementById("button_"+cell);
- if (oslot_Button) {
- oslot_Button.className = "btn " + slot.color + " " + slot.state;
- oslot_Button.onmouseover = over_cell;
- oslot_Button.onmouseout = out_cell;
- if (slot.jid == "None") {
- oslot_Button.onclick = function() { return false; };
- } else {
- oslot_Button.job = slot.jid;
- oslot_Button.onclick = show_slot_job;
- }
- }
- var oslot_Name = document.getElementById("cell_name_"+cell);
- if (oslot_Name) {
- oslot_Name.innerHTML = slot.name;
- }
- var oslot_Machine = document.getElementById("cell_machine_"+cell);
- if (oslot_Machine) {
- oslot_Machine.innerHTML = slot.machine;
- }
- var oslot_Job = document.getElementById("cell_job_id_"+cell);
- if (oslot_Job) {
- oslot_Job.innerHTML = slot.job_id;
- }
- var oslot_State = document.getElementById("cell_state_"+cell);
- if (oslot_State) {
- oslot_State.innerHTML = slot.state;
- }
- var oslot_Activity = document.getElementById("cell_activity_"+cell);
- if (oslot_Activity) {
- oslot_Activity.innerHTML = slot.activity;
- }
- }
- setTimeout("get_slot_grid()", 2500);
-}
-function show_slot_job() {
- if ( typeof show_slot_job_url != "undefined" ) {
- var url = show_slot_job_url.replace("XXX", this.job);
- window.location.href = url;
- }
- return false;
-}
-
[SystemStatus.javascript]
function updateSystemStatus(id, system) {
updateStatus(id, system);
@@ -133,7 +86,7 @@
<h2>Memory/Load</h2>
{stats}
- {slot_grid}
+ {system_slot_map}
</td>
<td>
{freemem}
17 years, 1 month