rhmessaging commits: r3597 - in mgmt/trunk: mint/python/mint and 1 other directory.
by rhmessaging-commits@lists.jboss.org
Author: justi9
Date: 2009-08-31 11:06:39 -0400 (Mon, 31 Aug 2009)
New Revision: 3597
Modified:
mgmt/trunk/cumin/bin/cumin
mgmt/trunk/mint/python/mint/main.py
Log:
Also look for a cumin.conf file; no need to set the default mint home
Modified: mgmt/trunk/cumin/bin/cumin
===================================================================
--- mgmt/trunk/cumin/bin/cumin 2009-08-31 14:17:56 UTC (rev 3596)
+++ mgmt/trunk/cumin/bin/cumin 2009-08-31 15:06:39 UTC (rev 3597)
@@ -2,8 +2,6 @@
if [[ "$CUMIN_HOME" ]]; then
export MINT_HOME="$CUMIN_HOME"
-else
- export MINT_HOME="/var/lib/cumin"
fi
function die {
Modified: mgmt/trunk/mint/python/mint/main.py
===================================================================
--- mgmt/trunk/mint/python/mint/main.py 2009-08-31 14:17:56 UTC (rev 3596)
+++ mgmt/trunk/mint/python/mint/main.py 2009-08-31 15:06:39 UTC (rev 3597)
@@ -107,7 +107,10 @@
def init(self, opts=None):
super(MintConfig, self).init()
+ self.load_file(os.path.join(self.home, "etc", "cumin.conf"))
self.load_file(os.path.join(self.home, "etc", "mint.conf"))
+
+ self.load_file(os.path.join(os.path.expanduser("~"), ".cumin.conf"))
self.load_file(os.path.join(os.path.expanduser("~"), ".mint.conf"))
if opts:
15 years, 3 months
rhmessaging commits: r3596 - in mgmt/trunk: rosemary and 1 other directories.
by rhmessaging-commits@lists.jboss.org
Author: justi9
Date: 2009-08-31 10:17:56 -0400 (Mon, 31 Aug 2009)
New Revision: 3596
Modified:
mgmt/trunk/parsley/Makefile
mgmt/trunk/rosemary/Makefile
mgmt/trunk/wooly/Makefile
Log:
Don't use the now removed python-compile wrapper
Modified: mgmt/trunk/parsley/Makefile
===================================================================
--- mgmt/trunk/parsley/Makefile 2009-08-31 14:17:22 UTC (rev 3595)
+++ mgmt/trunk/parsley/Makefile 2009-08-31 14:17:56 UTC (rev 3596)
@@ -6,7 +6,7 @@
lib := ${PYTHON_LIB_DIR}/${name}
build:
- ../bin/python-compile python
+ python -m compileall -x '/\.svn' -f python
install: build
install -d ${lib}
Modified: mgmt/trunk/rosemary/Makefile
===================================================================
--- mgmt/trunk/rosemary/Makefile 2009-08-31 14:17:22 UTC (rev 3595)
+++ mgmt/trunk/rosemary/Makefile 2009-08-31 14:17:56 UTC (rev 3596)
@@ -10,7 +10,7 @@
share := ${SHARE_DIR}/${name}
build:
- ../bin/python-compile python
+ python -m compileall -x '/\.svn' -f python
install: build
install -d ${lib}
Modified: mgmt/trunk/wooly/Makefile
===================================================================
--- mgmt/trunk/wooly/Makefile 2009-08-31 14:17:22 UTC (rev 3595)
+++ mgmt/trunk/wooly/Makefile 2009-08-31 14:17:56 UTC (rev 3596)
@@ -8,7 +8,7 @@
share := ${SHARE_DIR}/${name}
build:
- ../bin/python-compile python
+ python -m compileall -x '/\.svn' -f python
install: build
install -d ${lib}
15 years, 3 months
rhmessaging commits: r3595 - mgmt/trunk/bin.
by rhmessaging-commits@lists.jboss.org
Author: justi9
Date: 2009-08-31 10:17:22 -0400 (Mon, 31 Aug 2009)
New Revision: 3595
Modified:
mgmt/trunk/bin/find-code
Log:
Include Makefiles in 'code'
Modified: mgmt/trunk/bin/find-code
===================================================================
--- mgmt/trunk/bin/find-code 2009-08-27 19:52:28 UTC (rev 3594)
+++ mgmt/trunk/bin/find-code 2009-08-31 14:17:22 UTC (rev 3595)
@@ -3,5 +3,7 @@
exec find "${DEVEL_HOME}/" \
-regextype posix-awk \
-regex '.*\.(py|strings|sql|xml|js|css)$' \
- -or \
- -regex '.*/bin/[^/]+$' -executable -type f
+ -or -regex '.*/bin/[^/]+$' -executable -type f \
+ -or -name Makefile\* -type f
+
+# -path "**/.svn/**" -prune \
15 years, 3 months
rhmessaging commits: r3594 - in mgmt/trunk: cumin/python/cumin/grid and 3 other directories.
by rhmessaging-commits@lists.jboss.org
Author: justi9
Date: 2009-08-27 15:52:28 -0400 (Thu, 27 Aug 2009)
New Revision: 3594
Added:
mgmt/trunk/wooly/python/wooly/sql.py
Removed:
mgmt/trunk/cumin/python/cumin/visualizations.py
mgmt/trunk/cumin/python/cumin/visualizations.strings
Modified:
mgmt/trunk/cumin/python/cumin/config.py
mgmt/trunk/cumin/python/cumin/grid/collector.py
mgmt/trunk/cumin/python/cumin/grid/collector.strings
mgmt/trunk/cumin/python/cumin/grid/job.py
mgmt/trunk/cumin/python/cumin/grid/limit.py
mgmt/trunk/cumin/python/cumin/grid/limit.strings
mgmt/trunk/cumin/python/cumin/grid/main.py
mgmt/trunk/cumin/python/cumin/grid/model.py
mgmt/trunk/cumin/python/cumin/grid/negotiator.py
mgmt/trunk/cumin/python/cumin/grid/negotiator.strings
mgmt/trunk/cumin/python/cumin/grid/pool.py
mgmt/trunk/cumin/python/cumin/grid/pool.strings
mgmt/trunk/cumin/python/cumin/grid/scheduler.py
mgmt/trunk/cumin/python/cumin/grid/slot.py
mgmt/trunk/cumin/python/cumin/grid/slot.strings
mgmt/trunk/cumin/python/cumin/grid/submission.py
mgmt/trunk/cumin/python/cumin/grid/submitter.py
mgmt/trunk/cumin/python/cumin/inventory/main.py
mgmt/trunk/cumin/python/cumin/inventory/system.py
mgmt/trunk/cumin/python/cumin/inventory/system.strings
mgmt/trunk/cumin/python/cumin/main.py
mgmt/trunk/cumin/python/cumin/messaging/broker.py
mgmt/trunk/cumin/python/cumin/messaging/broker.strings
mgmt/trunk/cumin/python/cumin/messaging/brokergroup.py
mgmt/trunk/cumin/python/cumin/messaging/brokerlink.py
mgmt/trunk/cumin/python/cumin/messaging/connection.py
mgmt/trunk/cumin/python/cumin/messaging/exchange.py
mgmt/trunk/cumin/python/cumin/messaging/queue.py
mgmt/trunk/cumin/python/cumin/model.py
mgmt/trunk/cumin/python/cumin/parameters.py
mgmt/trunk/cumin/python/cumin/stat.py
mgmt/trunk/cumin/python/cumin/widgets.py
mgmt/trunk/cumin/python/cumin/widgets.strings
mgmt/trunk/wooly/python/wooly/__init__.py
mgmt/trunk/wooly/python/wooly/tables.py
mgmt/trunk/wooly/python/wooly/widgets.py
Log:
* Introduce a SqlDataSet object, for use as an interchangeable
backend to widgets
* Use a sqldataset to revamp the data source for the slot
visualization
* Eliminate most instances of *args to render and process methods;
they're nearly gone; much of this was in the grid module
* Introduce background-updated object stores for qmf grid limits and
jobs
* Consolidate sql connection getting on CuminModel
* Rework the Pool object to fetch its associated objects, negotiator,
collector, etc.
* Remove some Actions, which should no longer be used; there's more
work to do in this department
* Introduce a Task for setting concurrency limits, and use standard
task forms for the ui
* Add wooly logging
* Assorted formatting tweaks
* Move the slot visualization code to slot.py; remove
visualizations.py
* Make create submission a pool-level task
Modified: mgmt/trunk/cumin/python/cumin/config.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/config.py 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/config.py 2009-08-27 19:52:28 UTC (rev 3594)
@@ -53,7 +53,9 @@
enable_logging("cumin", self.log_level, self.log_file)
enable_logging("mint", self.log_level, self.log_file)
+ enable_logging("wooly", self.log_level, self.log_file)
if self.debug:
enable_logging("cumin", "debug", sys.stderr)
enable_logging("mint", "debug", sys.stderr)
+ enable_logging("wooly", "debug", sys.stderr)
Modified: mgmt/trunk/cumin/python/cumin/grid/collector.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/collector.py 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/grid/collector.py 2009-08-27 19:52:28 UTC (rev 3594)
@@ -75,18 +75,18 @@
self.view = CollectorView(app, "view", self.object)
self.add_mode(self.view)
-class CollectorStats(Widget):
- def __init__(self, app, name):
- super(CollectorStats, self).__init__(app, name)
+class CollectorOverview(Widget):
+ def __init__(self, app, name, collector):
+ super(CollectorOverview, self).__init__(app, name)
- self.add_child(StatSet(app, "stats", "general"))
+ self.add_child(StatSet(app, "stats", collector, "general"))
- chart = self.JobStackedChart(app, "jobs")
+ chart = self.JobStackedChart(app, "jobs", collector)
chart.stats = ("RunningJobs", "IdleJobs")
chart.chart_type = "stacked"
self.add_child(chart)
- chart = self.SlotStackedChart(app, "slots")
+ chart = self.SlotStackedChart(app, "slots", collector)
chart.stats = ("HostsClaimed", "HostsUnclaimed", "HostsOwner")
chart.chart_type = "stacked"
self.add_child(chart)
@@ -95,22 +95,22 @@
return "Statistics"
class JobStackedChart(StatFlashChart):
- def render_title(self, session, *args):
- return "Job Status"
+ def render_title(self, session):
+ return "Job status"
class SlotStackedChart(StatFlashChart):
def render_title(self, session, *args):
- return "Slot State"
+ return "Slot state"
class CollectorView(CuminView):
def __init__(self, app, name, collector):
- super(CollectorView, self).__init__(app, name)
+ super(CollectorView, self).__init__(app, name, collector)
self.tabs = TabbedModeSet(app, "tabs")
self.add_child(self.tabs)
- self.tabs.add_tab(CollectorStats(app, "stats"))
- self.tabs.add_tab(CuminDetails(app, "details"))
+ self.tabs.add_tab(CollectorOverview(app, "stats", collector))
+ self.tabs.add_tab(CuminDetails(app, "details", collector))
class CollectorStartForm(CuminTaskForm):
def __init__(self, app, name, task):
Modified: mgmt/trunk/cumin/python/cumin/grid/collector.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/collector.strings 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/grid/collector.strings 2009-08-27 19:52:28 UTC (rev 3594)
@@ -16,22 +16,18 @@
left outer join collector_stats as cs on cs.id = c.stats_curr_id
{sql_where}
-[CollectorStats.html]
+[CollectorOverview.html]
<table class="twocol">
<tbody>
<tr>
<td>
- <h2>Collector Stats</h2>
+ <h2>Statistics</h2>
{stats}
</td>
<td>
- <div>
- {jobs}
- </div>
- <div>
- {slots}
- </div>
- </td>
+ <div>{jobs}</div>
+ <div>{slots}</div>
+ </td>
</tr>
</tbody>
</table>
Modified: mgmt/trunk/cumin/python/cumin/grid/job.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/job.py 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/grid/job.py 2009-08-27 19:52:28 UTC (rev 3594)
@@ -1,4 +1,5 @@
import logging
+
from wooly import *
from wooly.widgets import *
from wooly.forms import *
@@ -23,8 +24,8 @@
self.submission = submission
- self.update_enabled = False
self.defer_enabled = True
+ self.update_enabled = True
col = self.CustomIdColumn(app, "name")
self.add_column(col)
@@ -59,14 +60,17 @@
def do_get_items(self, session, *args):
submission = self.submission.get(session)
- scheduler = submission.scheduler
- action = self.app.model.scheduler.GetJobs
- jobs = action.qmfcall(scheduler, submission.Name)
+ jobs = self.app.model.get_submission_jobs(submission)
+
+ if jobs is None:
+ return ()
+
return jobs
def filter_item(self, session, item):
state = self.phase.get(session)
+
if state == "All":
return True
@@ -261,19 +265,16 @@
class JobGroupView(CuminView):
def __init__(self, app, name, pool):
- super(JobGroupView, self).__init__(app, name)
+ super(JobGroupView, self).__init__(app, name, pool)
- summary = CuminSummary(app, "summary")
- self.add_child(summary)
+ self.tabs = TabbedModeSet(app, "tabs")
+ self.add_child(self.tabs)
- self.__tabs = TabbedModeSet(app, "tabs")
- self.add_child(self.__tabs)
+ self.tabs.add_tab(JobGroupStats(app, "stats"))
+ self.tabs.add_tab(JobGroupJobSet(app, "jobs", pool))
+ self.tabs.add_tab(JobGroupSystemSet(app, "systems"))
+ #self.tabs.add_tab(CuminDetails(app, "details"))
- self.__tabs.add_tab(JobGroupStats(app, "stats"))
- self.__tabs.add_tab(JobGroupJobSet(app, "jobs", pool))
- self.__tabs.add_tab(JobGroupSystemSet(app, "systems"))
- #self.__tabs.add_tab(CuminDetails(app, "details"))
-
class JobGroupStats(Widget):
def __init__(self, app, name):
super(JobGroupStats, self).__init__(app, name)
@@ -380,15 +381,12 @@
self.scheduler = SchedulerParameter(app, "scheduler")
self.add_parameter(self.scheduler)
- self.view = JobView(app, "view")
+ self.view = JobView(app, "view", self.object)
self.add_mode(self.view)
- self.__edit_ads = JobAdsEditor(app, "editads")
+ self.__edit_ads = JobAdsEditor(app, "editads", self.object)
self.add_mode(self.__edit_ads)
- self.__system = SystemFrame(app, "system")
- self.add_mode(self.__system)
-
def show_ads_edit(self, session):
self.page.set_frame(session, self.__edit_ads)
return self.__edit_ads.show(session)
@@ -399,11 +397,6 @@
self.__job.set_switch(session, "group")
return self.__job.show(session)
- def show_system(self, session, system):
- frame = self.__system.show(session)
- frame.set_object(session, system)
- return self.page.set_frame(session, frame)
-
def get_href(self, session, job, scheduler):
branch = session.branch()
self.show_object(branch, job)
@@ -411,22 +404,24 @@
return branch.marshal()
class JobView(CuminView):
- def __init__(self, app, name):
- super(JobView, self).__init__(app, name)
+ def __init__(self, app, name, job):
+ super(JobView, self).__init__(app, name, job)
self.tabs = TabbedModeSet(app, "tabs")
self.add_child(self.tabs)
- self.tabs.add_tab(JobAdsViewer(app, "jobads"))
- self.tabs.add_tab(JobOutput(app, "output"))
- #self.tabs.add_tab(JobSystemSet(app, "systems"))
- #self.tabs.add_tab(CuminDetails(app, "details"))
+ self.tabs.add_tab(JobAdsViewer(app, "jobads", job))
+ self.tabs.add_tab(JobOutput(app, "output", job))
+ #self.tabs.add_tab(JobSystemSet(app, "systems", job))
+ #self.tabs.add_tab(CuminDetails(app, "details", job))
class JobSystemSet(SystemSet):
- def get_args(self, session):
- return self.frame.get_args(session)
+ def __init__(self, app, name, job):
+ super(JobSystemSet, self).__init__(app, name)
- def render_sql_where(self, session, job):
+ self.job = job
+
+ def render_sql_where(self, session):
return """
where exists
(select 1
@@ -434,29 +429,31 @@
where system = s.node_name and job_id = %(id)s)
"""
- def get_sql_values(self, session, job):
+ def get_sql_values(self, session):
+ job = self.job.get(session)
return {"id": "%i.%i" % (job.ClusterId, job.ProcId)}
class JobAdsSet(PropertySet):
- def __init__(self, app, name):
- super(JobAdsSet, self).__init__(app, name, )
+ types = {0: "expression",
+ 1: "integer",
+ 2: "float",
+ 3: "string"}
- self.types = {0: "expression",
- 1: "integer",
- 2: "float",
- 3: "string"}
- def get_args(self, session):
- return self.frame.get_args(session)
+ def __init__(self, app, name, job):
+ super(JobAdsSet, self).__init__(app, name)
- def do_get_items(self, session, job, scheduler):
- items = self.items.get(session)
- if not items:
- items = self.gen_items(session, job, scheduler)
- # cache the items
- self.items.set(session, items)
+ self.job = job
- return items
+ def do_get_items(self, session):
+ job = self.job.get(session)
+ cls = self.app.model.get_class_by_object(job)
+ job_ads = self.get_raw_ads(session, job)
+
+ return [self.gen_item(x, job_ads[x]["VALUE"], cls,
+ dtype=self.types[job_ads[x]["TYPE"]])
+ for x in job_ads]
+
def get_raw_ads(self, session, job, scheduler):
if not scheduler:
schedulers = Scheduler.select()
@@ -481,13 +478,16 @@
#return [self.gen_item(x, job_ads[x], cls) for x in job_ads]
#
- def gen_item(self, name, value, cls, path=None, dtype=None, error=None, orig=None):
- """ Generate a dict with name, value, type, error, path, property, orig
+ def gen_item(self, name, value, cls, path=None, dtype=None,
+ error=None, orig=None):
+ """ Generate a dict with name, value, type, error, path,
+ property, orig
- This is called with raw GetAd data and with processed data from
- a form submit. With raw data, only the name and value will be present.
- With form data, we might have a path, dtype, or error. dtype is the
- data type that was remembered from the raw data.
+ This is called with raw GetAd data and with processed data
+ from a form submit. With raw data, only the name and value
+ will be present. With form data, we might have a path,
+ dtype, or error. dtype is the data type that was
+ remembered from the raw data.
"""
idict = dict()
@@ -495,18 +495,22 @@
idict["value"] = value
idict["orig"] = value
idict["type"] = dtype
+
if dtype == "string":
idict["value"] = strip_string_quotes(value)
+
if orig:
idict["orig"] = orig
- if error:
- if "error" in error:
- idict["error"] = error["error"]
+ if error and "error" in error:
+ idict["error"] = error["error"]
+
if name in cls.ad_properties_by_name:
idict["property"] = cls.ad_properties_by_name[name]
+
if path:
idict["path"] = path
+
return idict
class JobPropertyRenderer(TemplateRenderer):
@@ -544,13 +548,15 @@
return property.description
class JobAdsGroups(Widget):
- def __init__(self, app, name):
+ def __init__(self, app, name, job):
super(JobAdsGroups, self).__init__(app, name)
+ self.job = job
+
self.group_tmpl = Template(self, "group_html")
def render_groups(self, session):
- job = self.frame.get_args(session)[0]
+ job = self.job.get(session)
groups = self.app.model.get_ad_groups()
writer = Writer()
for group in groups:
@@ -570,12 +576,12 @@
return writer.to_string()
class JobAdsViewer(JobAdsSet):
- def __init__(self, app, name):
- super(JobAdsViewer, self).__init__(app, name)
+ def __init__(self, app, name, job):
+ super(JobAdsViewer, self).__init__(app, name, job)
self.item_renderer = JobPropertyRenderer(self, "property_html")
- self.groups = JobAdsGroups(app, "groups");
+ self.groups = JobAdsGroups(app, "groups", job);
self.add_child(self.groups)
self.wait = Wait(app, "wait")
@@ -583,13 +589,10 @@
self.defer_enabled = True
- def get_args(self, session):
- return self.frame.get_args(session)
-
- def render_title(self, session, job):
+ def render_title(self, session):
return "Attributes"
- def render_edit_ads_url(self, session, job):
+ def render_edit_ads_url(self, session):
branch = session.branch()
self.frame.show_ads_edit(branch)
return branch.marshal()
@@ -598,6 +601,7 @@
job = args[0]
group = args[1]
group_items = list()
+
if job:
scheduler = self.frame.scheduler.get(session)
all_items = super(JobAdsViewer, self).do_get_items(session, job, scheduler)
@@ -612,9 +616,9 @@
return group_items
-class JobAdsEditor(CuminForm, JobAdsViewer):
- def __init__(self, app, name):
- super(JobAdsEditor, self).__init__(app, name)
+class JobAdsEditor(JobAdsViewer, CuminForm):
+ def __init__(self, app, name, job):
+ super(JobAdsEditor, self).__init__(app, name, job)
# the parameter that will hold all the field values
self.ads = DictParameter(app, "params")
@@ -630,10 +634,12 @@
group = args[1]
cls = self.app.model.job
ads = self.ads.get(session)
+
if len(ads):
return [self.gen_item(x, ads[x]["value"], cls, path=self.ads.path,
- dtype=ads[x]["type"], error=ads[x], orig=ads[x]["orig"]) for x in ads
- if self.is_group(x, cls, group)]
+ dtype=ads[x]["type"], error=ads[x],
+ orig=ads[x]["orig"]) for x in ads
+ if self.is_group(x, cls, group)]
else:
scheduler = self.frame.scheduler.get(session)
items = super(JobAdsEditor, self).do_get_items(session, args)
@@ -734,9 +740,11 @@
return file and "loading..." or "Output, Error, and UserLog file names are invalid."
class JobOutput(Form):
- def __init__(self, app, name):
+ def __init__(self, app, name, job):
super(JobOutput, self).__init__(app, name)
+ self.job = job
+
self.which_file = self.FileSwitch(app, "file")
self.add_child(self.which_file)
@@ -749,24 +757,21 @@
self.output = OutputFile(app, "job_output", self.which_file, self.first_last)
self.add_child(self.output)
- self.ads = JobAdsSet(app, "ads")
+ self.ads = JobAdsSet(app, "ads", self.job)
- def get_args(self, session):
- return self.frame.get_args(session)
-
- def render_title(self, session, *args):
+ def render_title(self, session):
return "Output"
- def render_is_tail(self, session, *args):
+ def render_is_tail(self, session):
tail = self.first_last.get(session)
return tail == "t" and "1" or "0"
- def render_out_time(self, session, *args):
+ def render_out_time(self, session):
now = datetime.now()
return fmt_datetime(now, sec=True)
- def do_process(self, session, *args):
- job = args[0]
+ def do_process(self, session):
+ job = self.job.get(session)
out_file = None
user_file = None
@@ -794,7 +799,7 @@
if self.which_file.is_bad(user_file):
self.which_file.disable(session, "u")
- return super(JobOutput, self).do_process(session, *args)
+ return super(JobOutput, self).do_process(session)
class FetchButton(FormButton):
def render_content(self, session):
Modified: mgmt/trunk/cumin/python/cumin/grid/limit.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/limit.py 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/grid/limit.py 2009-08-27 19:52:28 UTC (rev 3594)
@@ -14,54 +14,17 @@
from job import *
strings = StringCatalog(__file__)
-log = logging.getLogger("cumin.Limits")
+log = logging.getLogger("cumin.limit")
-class LimitActions(object):
- def fetch_limits(self, session):
- negotiator = self.get_negotiator(session)
- if negotiator:
- limits = self.get_raw_limits(session, negotiator)
- if "timeout" in limits:
- del limits["timeout"]
- return limits
- else:
- return dict()
+class LimitSet(ItemTable):
+ def __init__(self, app, name, negotiator):
+ super(LimitSet, self).__init__(app, name)
- def get_negotiator(self, session):
-#TODO: find better way to get the negotiator. from pool perhaps?
- pool = self.frame.get_args(session)[0]
- most_recent = None
- negotiators = Negotiator.select("pool='%s'" % pool.id)
- for negotiator in negotiators:
- if negotiator.qmfBrokerId:
- if not most_recent:
- most_recent = negotiator
- try:
- if negotiator.statsCurr.qmfUpdateTime > \
- most_recent.statsCurr.qmfUpdateTime:
- most_recent = negotiator
- except:
- pass
+ self.negotiator = negotiator
- return most_recent
+ self.defer_enabled = True
+ self.update_enabled = True
- def set_limit(self, session, limit):
- negotiator = self.get_negotiator(session)
- action = self.app.model.limit.setlimit
- action.invoke(limit, negotiator)
-#TODO: this probably shouldn't be called until after the invoke completes
- def completion():
- pass
- negotiator.Reconfig(self.app.model.mint.model, completion)
-
- def get_raw_limits(self, session, negotiator):
- action = self.app.model.negotiator.GetLimits
- return action.do_invoke(negotiator)
-
-class LimitsSet(ItemTable, LimitActions):
- def __init__(self, app, name):
- super(LimitsSet, self).__init__(app, name)
-
col = self.NameColumn(app, "name")
self.add_column(col)
self.set_default_column(col)
@@ -74,38 +37,37 @@
col.alignment = "right"
self.add_column(col)
- self.limits = self.Limits(self, "limits")
- self.add_attribute(self.limits)
-
self.limit_count = self.LimitCount(app, "limit_count")
self.add_child(self.limit_count)
- def do_get_items(self, session, *args):
- limits = self.limits.get(session)
- if not len(limits):
- limits = self.fetch_limits(session)
- self.limits.set(session, limits)
+ def do_get_items(self, session):
+ negotiator = self.negotiator.get(session)
+
+ limits = self.app.model.get_negotiator_limits(negotiator)
+
+ if limits is None:
+ return ()
+
keys = limits.keys()
keys.sort()
- return [{"name":x, "curr":limits[x]["CURRENT"], "max":limits[x]["MAX"]} for x in keys]
+ return [{"name": x,
+ "curr": limits[x]["CURRENT"],
+ "max": limits[x]["MAX"]}
+ for x in keys]
+
def render_title(self, session):
return self.limit_count.render(session)
class LimitCount(Widget):
def __init__(self, app, name):
- super(LimitsSet.LimitCount, self).__init__(app, name)
+ super(LimitSet.LimitCount, self).__init__(app, name)
+
self.defer_enabled = True
+ self.update_enabled = True
def render_count(self, session):
- negotiator = self.parent.get_negotiator(session)
- action = self.app.model.negotiator.GetLimits
- limits = action.do_invoke(negotiator)
- if "timeout" in limits:
- val = 0
- else:
- val = len(limits)
- return str(val)
+ return len(self.parent.get_items(session))
class NameColumn(ItemTableColumn):
def render_title(self, session, data):
@@ -128,144 +90,59 @@
def get_default(self, session):
return dict()
-class LimitsFrame(CuminFrame, LimitActions):
- def __init__(self, app, name, pool):
- super(LimitsFrame, self).__init__(app, name)
+class LimitFrame(CuminFrame):
+ def __init__(self, app, name, negotiator):
+ super(LimitFrame, self).__init__(app, name)
- self.object = LimitParameter(app, "id")
+ self.object = Parameter(app, "limit")
self.add_parameter(self.object)
- self.view = LimitsView(app, "view", pool)
+ self.view = LimitView(app, "view", negotiator, self.object)
self.add_mode(self.view)
- self.edit = LimitEdit(app, "edit")
- self.add_mode(self.edit)
+class NegotiatorLimitSetForm(CuminForm):
+ def __init__(self, app, name, task):
+ super(LimitEdit, self).__init__(app, name)
- def get_object(self, session):
- obj = self.object.get(session)
- if not getattr(obj, "name", None):
- limits = self.fetch_limits(session)
- obj.name = obj.id
- obj.curr = limits[obj.id]["CURRENT"]
- obj.max = limits[obj.id]["MAX"]
- self.object.set(session, obj)
+ self.task = task
- return obj
+ self.negotiator = NegotiatorParameter(app, "negotiator")
+ self.add_parameter(self.negotiator)
+ self.limit_name = Parameter("name")
+ self.add_parameter(self.limit_name)
-class LimitEdit(CuminForm):
- def __init__(self, app, name):
- super(LimitEdit, self).__init__(app, name)
-
- self.max = Parameter(app, "max")
+ self.limit_max = Parameter(app, "max")
self.add_parameter(self.max)
- self.error = self.Errors(self, "error")
- self.add_attribute(self.error)
+ def render_title(self, session):
+ negotiator = self.negotiator.get(session)
+ name = self.limit_name.get(session)
+
+ return self.task.get_description(session, (negotiator, name))
- self.error_tmpl = Template(self, "error_html")
+ def xxx_render_inline_help(self, session):
+ return "Set the maximum number of jobs that can run " + \
+ "concurrently using this limiter."
- class Errors(Attribute):
- def get_default(self, session):
- return dict()
+ def process_submit(self, session):
+ negotiator = self.negotiator.get(session)
+ name = self.limit_name.get(session)
+ max = self.limit_max.get(session)
- def get_args(self, session):
- return self.frame.get_args(session)
+ self.check()
- def render_title(self, session, *args):
- return "Edit Concurrency Limit '%s'" % args[0].id
+ # XXX add errors
+ # 1. max is float
+ # 2. max > 1.0 and max < 99999.0
- def render_input_id(self, session, *args):
- return self.max.path
+ if not self.errors.get(session):
+ self.task.invoke(session, negotiator, name, max)
+ self.task.exit_with_redirect(session, (negotiator, name))
- def render_label(self, session, *args):
- return "Maximum Allowance"
+class LimitView(CuminView):
+ def __init__(self, app, name, negotiator, limit):
+ super(LimitView, self).__init__(app, name, None)
- def render_input_name(self, session, *args):
- return self.max.path
-
- def render_input_value(self, session, *args):
- max = self.max.get(session)
- if not max:
- max = args[0].max
- return str(max)
-
- def render_inline_help(self, session, *args):
- return "Set the maximum number of jobs that can run concurrently using this limiter."
-
- def render_limit_error(self, session, *args):
- error = self.error.get(session)
- if "max" in error:
- writer = Writer()
- self.error_tmpl.render(writer, session, *args)
- return writer.to_string()
-
- def render_error(self, session, *args):
- error = self.error.get(session)
- if "max" in error:
- return error["max"]
-
- def render_original_value(self, session, *args):
- error = self.error.get(session)
- if "max" in error:
- return "Original value was %s" % str(args[0].max)
-
- def process_submit(self, session, *args):
- max = self.max.get(session)
- fmax = 0
- errors = False
- try:
- fmax = float(max)
- if fmax < 1.0 or fmax > 99999.0:
- raise "out of bounds"
- except:
- errors = True
- error = self.error.get(session)
- error["max"] = "Numeric value between 1 and 99999 expected"
- self.error.set(session, error)
-
- if not errors:
- limit = args[0]
- limit.max = fmax
- self.frame.set_limit(session, limit)
- self.process_cancel(session, *args)
-
-class LimitsView(CuminView):
- def __init__(self, app, name, pool):
- super(LimitsView, self).__init__(app, name)
-
self.tabs = TabbedModeSet(app, "tabs")
self.add_child(self.tabs)
-
- jobs = LimitsJobSet(app, "jobs", pool)
- self.tabs.add_tab(jobs)
-
- details = CuminDetails(app, "details")
- self.tabs.add_tab(details)
-
-class LimitsJobSet(JobTab):
- def get_visible_columns(self, session):
- return self.get_request_visible_columns(session,
- ["custom_group",
- "scheduler",
- "submitter"])
-
- def get_sql_values(self, session, *args):
- pass
-
- def render_sql_where(self, session, limit):
- phase_sql = self.get_phase_sql(session)
- limits_sql = self.get_limits_sql(session, limit)
- return "where %s" % " and ".join([phase_sql, limits_sql])
-
- def render_title(self, session, limit):
- limits_sql = self.get_limits_sql(session, limit)
- return "Jobs %s" % fmt_count(Job.select(limits_sql).count())
-
- def render_count(self, session, *args):
- str = super(LimitsJobSet, self).render_count(session, *args)
- return "%s with Concurrency Limit '%s'" % (str, args[0].id)
-
- def get_limits_sql(self, session, limit):
- x = limit.id
- return "concurrency_limits similar to '(%s|%s,%%|%%,%s|%%,%s,%%)'" % (x, x, x, x)
Modified: mgmt/trunk/cumin/python/cumin/grid/limit.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/limit.strings 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/grid/limit.strings 2009-08-27 19:52:28 UTC (rev 3594)
@@ -1,101 +1,6 @@
-[LimitsSet.html]
-<table class="mobjects">
- <thead>
- <tr>
- <th class="setnav" colspan="{column_count}">
- {count}
- </th>
- </tr>
- <tr>{headers}</tr>
- </thead>
- <tbody>{items}</tbody>
-</table>
-
-
[LimitCount.html]
<span id="{id}">Limits <span class="count">({count})</span></span>
[LimitCount.deferred_html]
<span id="{id}">Limits <span class="count">(?)</span></span>
-[LimitEdit.css]
-form.limitform {
- /* padding: 1em; */
-}
-
-form.limitform div.label, form.limitform div.input {
- float: left;
- height: 3em;
- margin-left: 1em;
-}
-
-form.limitform div.input input {
- position: relative;
- top: -0.2em;
- width: 4em;
-}
-
-form.limitform div.foot {
- clear: left;
-}
-
-form.limitform div.help {
- margin: 0.5em 1em 1em 0;
-}
-
-form.limitform div.original_value {
- color: #333;
- font-size: 0.9em;
- font-style: italic;
-}
-
-[LimitEdit.html]
-<form id="{id}" class="mform limitform" method="post" action="?">
- <div class="head">
- <h1>{title}</h1>
- </div>
- <div class="body">
- <div class="help">
- {inline_help}
- </div>
- <div class="label">
- <label for="{input_id}">{label}</label>
- </div>
- <div class="input">
- <input id="{input_id}" type="text" name="{input_name}" value="{input_value}" />
- <div class="original_value">{original_value}</div>
- </div>{limit_error}
- <div style="clear:both;"><!-- --></div>
- </div>
- <div class="foot">
- {help} {submit} {cancel}
- </div>
- <div>{hidden_inputs}</div>
-</form>
-
-[LimitEdit.error_html]
-<ul class="errors"><li>{error}</li></ul>
-
-[LimitsJobSet.html]
-<form id="{id}" method="post" action="?">
-<div class="rfloat">{phase}</div>
-
- <div class="sactions" style="clear:right;">
- <h2>Act on Selected Jobs:</h2>
- {hold} {release} {remove}
- </div>
-
- <table class="mobjects">
- <thead>
- <tr>
- <th class="setnav" colspan="{column_count}">
- <div class="rfloat">{page}</div>
- {count}
- </th>
- </tr>
- <tr>{headers}</tr>
- </thead>
- <tbody>{items}</tbody>
- </table>
- <div>{hidden_inputs}</div>
-</form>
Modified: mgmt/trunk/cumin/python/cumin/grid/main.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/main.py 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/grid/main.py 2009-08-27 19:52:28 UTC (rev 3594)
@@ -13,6 +13,9 @@
def init(self, app):
self.see_pools = SeePoolsTask(app, None)
+ pool = app.model.pool
+ self.submission_add = SubmissionAddTask(app, pool)
+
job = app.model.job
self.job_hold = JobHoldTask(app, job)
self.job_set_hold = JobSetHoldTask(app, job)
@@ -27,7 +30,6 @@
self.scheduler_stop = SchedulerStopTask(app, scheduler)
self.scheduler_set_start = SchedulerSetStartTask(app, scheduler)
self.scheduler_set_stop = SchedulerSetStopTask(app, scheduler)
- self.submission_add = SubmissionAddTask(app, scheduler)
collector = app.model.collector
self.collector_start = CollectorStartTask(app, collector)
@@ -52,6 +54,9 @@
app.main_page.main.grid = self.frame
app.main_page.main.add_tab(self.frame)
+ self.pool_slots_page = PoolSlotMapPage(app, "poolslots.png")
+ app.add_page(self.pool_slots_page)
+
module = GridModule()
class GridFrame(CuminFrame):
Modified: mgmt/trunk/cumin/python/cumin/grid/model.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/model.py 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/grid/model.py 2009-08-27 19:52:28 UTC (rev 3594)
@@ -130,6 +130,29 @@
def do_enter(self, session, objects):
self.form.object.set(session, objects)
+class NegotiatorLimitSetTask(QmfTask):
+ def __init__(self, app, cls):
+ super(NegotiatorLimitSetTask, self).__init__(app, cls)
+
+ self.form = NegotiatorLimitSetForm(app, "negotiator_limit_set", self)
+
+ def do_enter(self, session, limit):
+ self.form.negotiator.set(session, limit[0])
+ self.form.limit_name.set(session, limit[1])
+
+ def get_title(self, session):
+ return "Set limit"
+
+ def do_invoke(self, completion, session, negotiator, name, max):
+ assert isinstance(negotiator, Negotiator)
+
+ negotiator.SetLimit(self.app.model.mint.model, completion, name, max)
+
+ def completion():
+ pass
+
+ negotiator.Reconfig(self.app.model.mint.model, completion)
+
class CollectorStartTask(QmfTask):
def __init__(self, app, cls):
super(CollectorStartTask, self).__init__(app, cls)
Modified: mgmt/trunk/cumin/python/cumin/grid/negotiator.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/negotiator.py 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/grid/negotiator.py 2009-08-27 19:52:28 UTC (rev 3594)
@@ -82,16 +82,16 @@
class NegotiatorView(CuminView):
def __init__(self, app, name, negotiator):
- super(NegotiatorView, self).__init__(app, name)
+ super(NegotiatorView, self).__init__(app, name, negotiator)
- self.__tabs = TabbedModeSet(app, "tabs")
- self.add_child(self.__tabs)
+ self.tabs = TabbedModeSet(app, "tabs")
+ self.add_child(self.tabs)
- overview = NegotiatorOverviewTab(app, "overview", negotiator)
- self.__tabs.add_tab(overview)
+ self.overview = NegotiatorOverview(app, "overview", negotiator)
+ self.tabs.add_tab(self.overview)
- details = CuminDetails(app, "details")
- self.__tabs.add_tab(details)
+ self.details = CuminDetails(app, "details", negotiator)
+ self.tabs.add_tab(self.details)
class QmfGroupColumn(ItemTableColumn):
def __init__(self, app, name, getter, negotiator, task):
@@ -136,9 +136,9 @@
def fmt_hover(self, group):
return "Edit the %s" % self.title
-class NegotiatorOverviewTab(ItemTable):
+class NegotiatorOverview(ItemTable):
def __init__(self, app, name, negotiator):
- super(NegotiatorOverviewTab, self).__init__(app, name)
+ super(NegotiatorOverview, self).__init__(app, name)
self.update_enabled = False
self.defer_enabled = True
@@ -192,13 +192,13 @@
def render_title(self, session):
return "Group Configuration"
- def render_class(self, session, *args):
+ def render_class(self, session):
return "class=\"mobjects\""
- def render_deferred_content(self, session, *args):
+ def render_deferred_content(self, session):
return "Loading..."
- def do_get_items(self, session, *args):
+ def do_get_items(self, session):
groups = self.group_helper.get_group_names(session)
users = self.group_helper.get_users(session, groups)
self.expand.initialize(session, groups, users)
@@ -223,7 +223,7 @@
return items
class ExpandColumn(ItemTableColumn):
- def render_title(self, session, *args):
+ def render_title(self, session):
return ""
def get_class_list(self, session):
@@ -236,7 +236,7 @@
return ""
class GroupColumn(ItemTableColumn):
- def render_title(self, session, *args):
+ def render_title(self, session):
return "Group"
def render_content(self, session, group):
@@ -610,7 +610,8 @@
self.quotas = ListParameter(app, "quotas", quota)
self.add_parameter(self.quotas)
- self.chart = PriorityPieChart(app, "chart", self.group_helper)
+ self.chart = PriorityPieChart \
+ (app, "chart", self.object, self.group_helper)
self.add_child(self.chart)
def render_title(self, session):
@@ -853,33 +854,31 @@
self.task.exit_with_redirect(session, negotiator)
class PriorityPieChart(StatFlashChart):
- def __init__(self, app, name, groups):
- super(PriorityPieChart, self).__init__(app, name)
+ def __init__(self, app, name, negotiator, groups):
+ super(PriorityPieChart, self).__init__(app, name, negotiator)
+ self.negotiator = negotiator
+
self.chart_type = "pie"
self.fullpageable = False
self.update_enabled = False
self.groups = groups
- def get_args(self, session):
- return (self.frame.object.get(session),)
-
- def render_title(self, session, object):
+ def render_title(self, session):
pass
- def render_duration(self, session, *args):
+ def render_duration(self, session):
pass
- def render_width(self, session, *args):
+ def render_width(self, session):
return 360
- def render_height(self, session, *args):
+ def render_height(self, session):
return 210
-
- def get_href_params(self, session, object):
- params = super(PriorityPieChart, self).get_href_params(session, object)
+ def get_href_params(self, session):
+ params = super(PriorityPieChart, self).get_href_params(session)
params.append("width=%i" % self.render_width(session))
params.append("height=%i" % self.render_height(session))
Modified: mgmt/trunk/cumin/python/cumin/grid/negotiator.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/negotiator.strings 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/grid/negotiator.strings 2009-08-27 19:52:28 UTC (rev 3594)
@@ -24,7 +24,7 @@
padding: 0.75em;
}
-[NegotiatorOverviewTab.html]
+[NegotiatorOverview.html]
<div id="{id}" class="CuminTable GroupTable">
<div class="sactions">
<h2>Actions:</h2>
Modified: mgmt/trunk/cumin/python/cumin/grid/pool.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/pool.py 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/grid/pool.py 2009-08-27 19:52:28 UTC (rev 3594)
@@ -3,13 +3,13 @@
from wooly.widgets import *
from wooly.forms import *
from wooly.resources import *
+from wooly.sql import *
from wooly.tables import *
from cumin.stat import *
from cumin.widgets import *
from cumin.parameters import *
from cumin.formats import *
from cumin.util import *
-from cumin.visualizations import SlotMap
from job import *
from scheduler import SchedulerSet, SchedulerFrame
@@ -17,10 +17,13 @@
from submitter import SubmitterSet, SubmitterFrame
from collector import CollectorSet, CollectorFrame
from negotiator import NegotiatorSet, NegotiatorFrame
-from limit import LimitsSet, LimitsFrame
-from slot import SlotSet, SlotFrame
+from limit import LimitSet, LimitFrame
+from slot import SlotSet, SlotFrame, SlotMap, SlotMapPage
+from cumin.widgets import Session
+
import cumin.model
+import main
strings = StringCatalog(__file__)
@@ -77,14 +80,18 @@
self.object = PoolParameter(app, "id")
self.add_parameter(self.object)
+ negotiator = PoolNegotiatorAttribute(app, "negotiator", self.object)
+ self.add_attribute(negotiator)
+
self.view = PoolView(app, "view", self.object)
self.add_mode(self.view)
self.job = JobFrame(app, "job")
self.add_mode(self.job)
- self.job_group = JobGroupFrame(app, "jobgroup", self.object)
- self.add_mode(self.job_group)
+ # XXX
+ #self.job_group = JobGroupFrame(app, "jobgroup", self.object)
+ #self.add_mode(self.job_group)
self.slot = SlotFrame(app, "slot")
self.add_mode(self.slot)
@@ -95,50 +102,55 @@
self.collector = CollectorFrame(app, "coll")
self.add_mode(self.collector)
- self.limit = LimitsFrame(app, "limit", self.object)
+ self.limit = LimitFrame(app, "limit", negotiator)
self.add_mode(self.limit)
self.negotiator = NegotiatorFrame(app, "neg")
self.add_mode(self.negotiator)
+ # XXX this shouldn't be necessary
def show_job_frame(self, session):
self.page.set_frame(session, self.job)
return self.job.show(session)
class PoolView(CuminView):
def __init__(self, app, name, pool):
- super(PoolView, self).__init__(app, name)
+ super(PoolView, self).__init__(app, name, pool)
self.pool = pool
+ negotiator = PoolNegotiatorAttribute(app, "negotiator", self.pool)
+ self.add_attribute(negotiator)
+
self.tabs = TabbedModeSet(app, "tabs")
self.add_child(self.tabs)
- stats = PoolStats(app, "stats")
- self.tabs.add_tab(stats)
+ self.overview = PoolOverview(app, "overview", self.pool)
+ self.tabs.add_tab(self.overview)
self.submissions = PoolSubmissionSet(app, "submissions", self.pool)
self.tabs.add_tab(self.submissions)
- self.slots = PoolSlotSet(app, "slots")
+ self.slots = PoolSlotSet(app, "slots", self.pool)
self.tabs.add_tab(self.slots)
- self.scheds = PoolSchedulerSet(app, "scheds", pool)
+ self.scheds = PoolSchedulerSet(app, "scheds", self.pool)
self.tabs.add_tab(self.scheds)
- self.negs = PoolNegotiatorSet(app, "negs", pool)
+ self.negs = PoolNegotiatorSet(app, "negs", self.pool)
self.tabs.add_tab(self.negs)
- self.colls = PoolCollectorSet(app, "colls", pool)
+ self.colls = PoolCollectorSet(app, "colls", self.pool)
self.tabs.add_tab(self.colls)
- self.limits = LimitsSet(app, "limits")
+ self.limits = LimitSet(app, "limits", negotiator)
self.tabs.add_tab(self.limits)
- def do_process(self, session, *args):
+ def do_process(self, session):
self.limits.limit_count.process(session)
- super(PoolView, self).do_process(session, *args)
+ super(PoolView, self).do_process(session)
+ # XXX get rid of these
def set_collector_tab(self, session):
self.colls.show(session)
@@ -212,63 +224,64 @@
return "Negotiators %s" % fmt_count(count)
class PoolSlotSet(SlotSet):
- def get_args(self, session):
- return self.frame.get_args(session)
+ def __init__(self, app, name, pool):
+ super(PoolSlotSet, self).__init__(app, name)
- def render_sql_where(self, session, pool):
+ self.pool = pool
+
+ def render_sql_where(self, session):
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):
+ def get_sql_values(self, session):
+ pool = self.pool.get(session)
return {"pool": pool.id}
- def render_title(self, session, pool):
- count = self.get_item_count(session, pool)
+ def render_title(self, session):
+ count = self.get_item_count(session)
return "Slots %s" % fmt_count(count)
def filter(self, session, system, slots):
return slots
-class PoolVisualization(PoolSlotSet):
- def __init__(self, vis, app, name):
- super(PoolVisualization, self).__init__(app, name)
- vis.add_visualization(self, name)
+ def render_sql_order_by(self, session):
+ return "order by machine, name asc"
- def get_info(self, session, id):
- pool = model.Pool.get(id)
- return self.get_items(session, pool)
+class PoolOverview(Widget):
+ def __init__(self, app, name, pool):
+ super(PoolOverview, self).__init__(app, name)
- def render_sql_limit(self, session, *args):
- pass
+ self.pool = pool
- def render_sql_orderby(self, session, *args):
- return "order by machine, name asc"
+ self.collector = PoolCollectorAttribute(app, "collector", self.pool)
+ self.add_attribute(self.collector)
-class PoolStats(Widget):
- def __init__(self, app, name):
- super(PoolStats, self).__init__(app, name)
+ self.grid = PoolGridAttribute(app, "grid", self.pool)
+ self.add_attribute(self.grid)
- stats = self.CollectorStatSet(app, "slot_stats", "general")
+ stats = StatSet(app, "collector_stats", self.collector, "general")
self.add_child(stats)
- stats = self.GridStats(app, "grid_stats")
+ stats = GridStats(app, "grid_stats", self.grid)
self.add_child(stats)
- slot_map = self.PoolSlotMap(app, "pool_slot_map")
+ slot_map = PoolSlotMap(app, "slot_map", self.pool)
self.add_child(slot_map)
- chart = self.JobStackedChart(app, "jobs")
+ chart = self.JobStackedChart(app, "jobs", self.collector)
chart.duration.param.default = "3600"
chart.stats = ("RunningJobs", "IdleJobs")
chart.chart_type = "stacked"
self.add_child(chart)
- chart = self.SlotFlashChart(app, "slots")
+ chart = self.SlotFlashChart(app, "slots", self.collector)
chart.stats = ("HostsClaimed", "HostsUnclaimed", "HostsOwner")
chart.chart_type = "stacked"
self.add_child(chart)
@@ -277,94 +290,61 @@
return "Overview"
def render_pool_name(self, session):
- pool = self.frame.get_args(session)[0]
- return pool.name
+ collector = self.collector.get(session)
+ return collector.Name
- def get_collector_args(self, session):
- args = self.frame.get_args(session)
- return (args[0].collector,)
-
- class CollectorStatSet(StatSet):
- def get_args(self, session):
- return self.parent.get_collector_args(session)
-
class JobStackedChart(StatFlashChart):
- def render_title(self, session, *args):
- return "Job Status"
+ def render_title(self, session):
+ return "Job status"
- def get_args(self, session):
- return self.parent.get_collector_args(session)
-
class SlotFlashChart(StatFlashChart):
- def render_title(self, session, *args):
- return "Slot State"
+ def render_title(self, session):
+ return "Slot state"
- def get_args(self, session):
- return self.parent.get_collector_args(session)
+class GridStats(Widget):
+ def __init__(self, app, name, grid):
+ super(GridStats, self).__init__(app, name)
- class GridStats(Widget):
- def __init__(self, app, name):
- super(PoolStats.GridStats, self).__init__(app, name)
+ self.grid = grid
- stats = self.GridStatSet(app, "stats", "general")
- self.add_child(stats)
+ stats = self.GridStatSet(app, "stats", self.grid, "general")
+ self.add_child(stats)
- chart = self.GridJobChart(app, "jobs_chart")
- chart.stats = ("NumJobs", "RunningJobs", "IdleJobs")
- self.add_child(chart)
+ chart = self.GridJobChart(app, "jobs_chart", self.grid)
+ chart.stats = ("NumJobs", "RunningJobs", "IdleJobs")
+ self.add_child(chart)
- chart = self.GridSubmitChart(app, "submit_chart")
- chart.stats = ("SubmitsAllowed", "SubmitsQueued", "SubmitsInProgress")
- self.add_child(chart)
+ chart = self.GridSubmitChart(app, "submit_chart", self.grid)
+ chart.stats = ("SubmitsAllowed", "SubmitsQueued", "SubmitsInProgress")
+ self.add_child(chart)
- def get_grid_args(self, session):
- pool = self.frame.get_args(session)[0]
+ def render_grid_name(self, session):
+ grid = self.grid.get(session)
- for grid in Grid.selectBy(Pool=pool.id):
- return (grid,)
-
- return ()
-
- def render_grid_name(self, session):
- grid = self.get_grid_args(session)[0]
+ if grid:
return grid.Name
- def render(self, session):
- args = self.get_grid_args(session)
- if len(args):
- return super(PoolStats.GridStats, self).render(session)
+ def do_render(self, session):
+ grid = self.grid.get(session)
- class GridJobChart(StatFlashChart):
- def render_title(self, session, object):
- return "Grid Jobs"
+ if grid:
+ return super(GridStats, self).do_render(session)
- def get_args(self, session):
- return self.parent.get_grid_args(session)
+ class GridJobChart(StatFlashChart):
+ def render_title(self, session):
+ return "Grid jobs"
- class GridSubmitChart(StatFlashChart):
- def render_title(self, session, object):
- return "Grid Submits"
+ class GridSubmitChart(StatFlashChart):
+ def render_title(self, session):
+ return "Grid submits"
- def get_args(self, session):
- return self.parent.get_grid_args(session)
+ class GridStatSet(StatSet):
+ def do_render(self, session):
+ grid = self.object.get(session)
- class GridStatSet(StatSet):
- def get_args(self, session):
- return self.parent.get_grid_args(session)
+ if grid:
+ return super(GridStats.GridStatSet, self).do_render(session)
- def render(self, session):
- args = self.parent.get_grid_args(session)
-
- if len(args):
- return super(PoolStats.GridStats.GridStatSet, self).render(session)
-
- class PoolSlotMap(SlotMap):
- def get_title_name(self, session, pool):
- return pool.name
-
- def render_slot_clip_size(self, session, *args):
- return 400
-
class PoolJobStats(CuminTable):
def render_sql_where(self, session, pool):
elems = list()
@@ -374,3 +354,45 @@
def get_sql_values(self, session, pool):
values = {"pool": pool.id}
return values
+
+class PoolSlotMap(SlotMap):
+ def __init__(self, app, name, pool):
+ super(PoolSlotMap, self).__init__(app, name)
+
+ self.pool = pool
+
+ def do_process(self, session):
+ super(PoolSlotMap, self).do_process(session)
+
+ pool = self.pool.get(session)
+
+ self.slots.add_where_expr(session, "s.pool = '%s'", pool.id)
+
+ def render_image_href(self, session):
+ pool = self.pool.get(session)
+
+ page = main.module.pool_slots_page
+ sess = Session(page)
+
+ page.pool.set(sess, pool)
+
+ return sess.marshal()
+
+class PoolSlotMapPage(SlotMapPage):
+ def __init__(self, app, name):
+ super(PoolSlotMapPage, self).__init__(app, name)
+
+ self.pool = PoolParameter(app, "id")
+ self.add_parameter(self.pool)
+
+ def do_process(self, session):
+ super(PoolSlotMapPage, self).do_process(session)
+
+ pool = self.pool.get(session)
+
+ # XXX The conditional is necessary because this page is
+ # overloaded to generate little dots, in which case it has no
+ # pool
+
+ if pool:
+ self.slots.add_where_expr(session, "s.pool = '%s'", pool.id)
Modified: mgmt/trunk/cumin/python/cumin/grid/pool.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/pool.strings 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/grid/pool.strings 2009-08-27 19:52:28 UTC (rev 3594)
@@ -33,33 +33,34 @@
[PoolJobStats.count_sql]
1
-[PoolStats.css]
-div#poolStats div.col1, div#poolStats div.col2 {
+[PoolOverview.css]
+div#PoolOverview div.col1, div#PoolOverview div.col2 {
float: left;
width: 47%;
}
-div#poolStats div.col1 {
+div#PoolOverview div.col1 {
padding-right: 2em;
}
-[PoolStats.html]
-<div id="poolStats">
+[PoolOverview.html]
+<div id="PoolOverview">
<div class="col1">
<h2>Statistics</h2>
- {slot_stats}
+ {collector_stats}
<div>{jobs}</div>
<div>{slots}</div>
{grid_stats}
</div>
<div class="col2">
- <div>{pool_slot_map}</div>
+ <h2>Slots</h2>
+ <div>{slot_map}</div>
</div>
</div>
<div style="clear:left;"><!-- --></div>
[GridStats.html]
<br/>
-<h2>External Cloud 'Amazon EC2'</h2>
+<h2>Stats for Grid {grid_name}</h2>
{stats}
<div>{jobs_chart}</div>
<div>{submit_chart}</div>
Modified: mgmt/trunk/cumin/python/cumin/grid/scheduler.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/scheduler.py 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/grid/scheduler.py 2009-08-27 19:52:28 UTC (rev 3594)
@@ -1,14 +1,17 @@
import logging
+
from wooly import *
from wooly.widgets import *
from wooly.forms import *
from wooly.resources import *
from wooly.tables import *
-from cumin.stat import *
-from cumin.widgets import *
-from cumin.parameters import *
+
from cumin.formats import *
+from cumin.model import *
+from cumin.parameters import *
+from cumin.stat import *
from cumin.util import *
+from cumin.widgets import *
from job import *
from submitter import *
@@ -142,12 +145,12 @@
class SchedulerView(CuminView):
def __init__(self, app, name, scheduler):
- super(SchedulerView, self).__init__(app, name)
+ super(SchedulerView, self).__init__(app, name, scheduler)
self.tabs = TabbedModeSet(app, "tabs")
self.add_child(self.tabs)
- stats = SchedulerStats(app, "stats")
+ stats = SchedulerStats(app, "stats", scheduler)
self.tabs.add_tab(stats)
submissions = SchedulerSubmissionSet(app, "submissions", scheduler)
@@ -156,21 +159,23 @@
submitters = SchedulerSubmitterSet(app, "submitters", scheduler)
self.tabs.add_tab(submitters)
- details = CuminDetails(app, "details")
+ details = CuminDetails(app, "details", scheduler)
self.tabs.add_tab(details)
class SchedulerStats(Widget):
- def __init__(self, app, name):
+ def __init__(self, app, name, scheduler):
super(SchedulerStats, self).__init__(app, name)
- stats = StatSet(app, "general", "general")
+ stats = StatSet(app, "general", scheduler, "general")
self.add_child(stats)
- chart = self.UsersChart(app, "users")
+ chart = self.UsersChart(app, "users", scheduler)
+ chart.stats = ("NumUsers",)
chart.duration.param.default = "3600"
self.add_child(chart)
- chart = self.JobsChart(app, "jobs")
+ chart = self.JobsChart(app, "jobs", scheduler)
+ chart.stats = ("TotalRunningJobs", "TotalIdleJobs", "TotalHeldJobs")
chart.duration.param.default = "3600"
self.add_child(chart)
@@ -178,22 +183,11 @@
return "Statistics"
class UsersChart(StatFlashChart):
- def __init__(self, app, name):
- super(SchedulerStats.UsersChart, self).__init__(app, name)
-
- self.stats = ("NumUsers",)
-
- def render_title(self, session, sched):
+ def render_title(self, session):
return "Users"
class JobsChart(StatFlashChart):
- def __init__(self, app, name):
- super(SchedulerStats.JobsChart, self).__init__ \
- (app, name)
-
- self.stats = ("TotalRunningJobs", "TotalIdleJobs", "TotalHeldJobs")
-
- def render_title(self, session, sched):
+ def render_title(self, session):
return "Jobs"
class SchedulerSubmissionSet(SubmissionSet):
@@ -204,10 +198,6 @@
self.scheduler_col.visible = False
- task = main.module.submission_add
- link = TaskLink(app, "add", task, scheduler)
- self.links.add_child(link)
-
def render_sql_where(self, session):
return "where d.id = %(id)r"
@@ -268,4 +258,3 @@
self.object = ListParameter(app, "scheduler", item)
self.add_parameter(self.object)
-
Modified: mgmt/trunk/cumin/python/cumin/grid/slot.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/slot.py 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/grid/slot.py 2009-08-27 19:52:28 UTC (rev 3594)
@@ -10,22 +10,18 @@
from cumin.widgets import *
strings = StringCatalog(__file__)
-log = logging.getLogger("cumin.job")
+log = logging.getLogger("cumin.slot")
-# XXX marked for death
-class UniqueSlot(CuminTable):
- def get_recent_sql_where(self, session):
- return """
- s.qmf_update_time > now() - interval '60 minutes'
- """
+class SlotDataSet(CuminSqlDataSet):
+ def __init__(self, app):
+ super(SlotDataSet, self).__init__(app)
- def do_get_items(self, session, *args):
- cursor = super(UniqueSlot, self).do_get_items(session, *args)
- items = self.cursor_to_rows(cursor)
- self.items.set(session, items)
- return items
+ exprs = list()
+ exprs.append("s.qmf_update_time > now() - interval '60 minutes'")
-class SlotSet(UniqueSlot):
+ self.where_exprs.default = exprs
+
+class SlotSet(CuminTable):
def __init__(self, app, name):
super(SlotSet, self).__init__(app, name)
@@ -44,6 +40,11 @@
col = self.JobColumn(app, "job_id")
self.add_column(col)
+ def get_recent_sql_where(self, session):
+ return """
+ s.qmf_update_time > now() - interval '60 minutes'
+ """
+
class NameColumn(SqlTableColumn):
def render_title(self, session, data):
return "Name"
@@ -83,21 +84,6 @@
href = self.page.main.grid.pool.job.get_href(session, job, scheduler)
return fmt_link(href, data[self.name])
- def render_items(self, session, *args):
- """ overridden because a slotset query is expensive.
- the rows are cached """
-
- rows = self.get_items(session, *args)
- writer = Writer()
-
- for row in rows:
- self.item_tmpl.render(writer, session, row)
-
- return writer.to_string()
-
-class SlotStatSet(UniqueSlot):
- pass
-
class SlotFrame(CuminFrame):
def __init__(self, app, name):
super(SlotFrame, self).__init__(app, name)
@@ -105,30 +91,31 @@
self.object = SlotParameter(app, "id")
self.add_parameter(self.object)
- self.view = SlotView(app, "view")
+ self.view = SlotView(app, "view", self.object)
self.add_mode(self.view)
class SlotView(CuminView):
- def __init__(self, app, name):
- super(SlotView, self).__init__(app, name)
+ def __init__(self, app, name, slot):
+ super(SlotView, self).__init__(app, name, slot)
- self.__tabs = TabbedModeSet(app, "tabs")
- self.add_child(self.__tabs)
+ self.tabs = TabbedModeSet(app, "tabs")
+ self.add_child(self.tabs)
- stats = SlotStats(app, "stats")
- self.__tabs.add_tab(stats)
+ stats = SlotStats(app, "stats", slot)
+ self.tabs.add_tab(stats)
- details = CuminDetails(app, "details")
- self.__tabs.add_tab(details)
+ details = CuminDetails(app, "details", slot)
+ self.tabs.add_tab(details)
class SlotStats(Widget):
- def __init__(self, app, name):
+ def __init__(self, app, name, slot):
super(SlotStats, self).__init__(app, name)
- stats = StatSet(app, "general", "load")
+ stats = StatSet(app, "general", slot, "load")
self.add_child(stats)
- chart = self.LoadChart(app, "chart")
+ chart = self.LoadChart(app, "chart", slot)
+ chart.stats = ("LoadAvg", "CondorLoadAvg")
chart.duration.param.default = "3600"
self.add_child(chart)
@@ -136,10 +123,263 @@
return "Statistics"
class LoadChart(StatFlashChart):
+ def render_title(self, session):
+ return "Load"
+
+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),
+ "Retiring": (.8, .2, .8),
+ None: (.8, .8, .8)}
+
+ max_width = 400
+ max_png_age = 30
+
+ def __init__(self, app, name):
+ super(SlotMapPage, self).__init__(app, name)
+
+ self.zoom_level = IntegerParameter(app, "zl")
+ self.zoom_level.default = 1
+ self.add_parameter(self.zoom_level)
+
+ self.zoom_x = IntegerParameter(app, "zx")
+ self.zoom_x.default = 0
+ self.add_parameter(self.zoom_x)
+
+ self.zoom_y = IntegerParameter(app, "zy")
+ self.zoom_y.default = 0
+ self.add_parameter(self.zoom_y)
+
+ self.dot = Parameter(app, "dot")
+ self.add_parameter(self.dot)
+
+ self.cache = ImageCache()
+ self.slots = SlotDataSet(app)
+
+ def get_content_type(self, session):
+ return "image/png"
+
+ def get_cache_control(self, session):
+ return "no-cache"
+
+ 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 do_render(self, session):
+ dot = self.dot.get(session)
+
+ if dot:
+ return self.render_dot(session, dot)
+
+ zl = self.zoom_level.get(session)
+ zx = self.zoom_x.get(session)
+ zy = self.zoom_y.get(session)
+
+ # determine if cached copy is recent enough
+ cached_png, args = self.get_cached(session, zl)
+
+ if cached_png:
+ self.set_cookie(session, args)
+ return cached_png
+
+ map = HeatMapChart(self.max_width, self.max_width)
+
+ cursor = self.slots.execute(session)
+ records = cursor.fetchall()
+
+ if len(records) == 0:
+ return
+
+ columns = [x[0] for x in cursor.description]
+ activity = columns.index("activity")
+ state = columns.index("state")
+
+ slots = [(self.interiors[x[activity]], x[state]) for x in records]
+ size = map.plot_slots(slots, zl, zx, zy)
+
+ args = (size, map.width, map.height, len(slots), map.rows, map.cols)
+ self.set_cookie(session, args)
+ self.cache_it(session, zl, map, args)
+
+ writer = Writer()
+ map.write(writer)
+ return writer.to_string()
+
+ def get_cached(self, session, zl):
+ filename = self.gen_filename(session)
+ return self.cache.find_recent(filename, self.max_png_age)
+
+ def cache_it(self, session, zl, map, args):
+ filename = self.gen_filename(session)
+ writer = self.cache.create_cache_file(filename, args)
+ map.write(writer)
+
+ def gen_filename(self, session):
+ return session.marshal()
+
+ def set_cookie(self, session, args):
+ cookie = "|".join((str(x) for x in args))
+ session.set_cookie("slot_info", cookie)
+
+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.slot_clip_size = 400
+
+ self.slots = SlotDataSet(app)
+
+ def render_image_href(self, session):
+ raise Exception("Not implemented")
+
+ def render_job_index_param(self, session):
+ return "xargs"
+
+ def render_slot_job_url(self, session):
+ job = Identifiable("XXX")
+ object = self.frame.object.get(session) # XXX eeks
+ try:
+ if isinstance(object, Sysimage):
+ scheduler = Scheduler.select("system='%s'" % object.nodeName)[0]
+ else:
+ scheduler = Scheduler.select("pool='%s'" % object.id)[0]
+ return self.page.main.grid.pool.job.get_href(session, job, scheduler)
+ except:
+ pass
+
+ def render_slot_clip_size(self, session):
+ return self.slot_clip_size
+
+ class SlotLegend(Widget):
def __init__(self, app, name):
- super(SlotStats.LoadChart, self).__init__(app, name)
+ super(SlotMap.SlotLegend, self).__init__(app, name)
- self.stats = ("LoadAvg", "CondorLoadAvg")
+ self.states = self.SlotStates(app, "slot_states")
+ self.add_child(self.states)
- def render_title(self, session, sched):
- return "Load"
+ 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_item_initial(self, session, state):
+ return state[0]
+
+ def render_item_title(self, session, state):
+ return state
+
+ class SlotActivities(ItemSet):
+ activities = (("Idle", "clear"),
+ ("Busy", "green"),
+ ("Suspended", "red"),
+ ("Vacating", "orange"),
+ ("Killing", "blue"),
+ ("Benchmarking", "yellow"),
+ ("Retiring", "purple"),
+ ("Unknown", "grey"))
+
+ def render_item_size(self, session, activity):
+ return 12
+
+ def do_get_items(self, session):
+ return self.activities
+
+ def render_item_title(self, session, activity):
+ return activity[0]
+
+ def render_item_href(self, session, activity):
+ params = list()
+ params.append("dot=%s" % activity[0])
+
+ return "poolslots.png?" + ";".join(params)
+
+ 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.index = IntegerParameter(app, "i")
+ self.add_parameter(self.index)
+
+ self.slot = Attribute(app, "slot")
+ self.add_attribute(self.slot)
+
+ self.info_div_tmpl = Template(self, "bg_html")
+
+ def do_render(self, session):
+ index = self.index.get(session)
+
+ if index is not None:
+ self.parent.slots.limit.set(session, 1)
+ self.parent.slots.offset.set(session, index)
+
+ cursor = self.parent.slots.execute(session)
+
+ data = dict()
+ names = [x[0] for x in cursor.description]
+ values = cursor.fetchone()
+
+ for name, value in zip(names, values):
+ data[name] = value
+
+ self.slot.set(session, data)
+
+ writer = Writer()
+ self.info_div_tmpl.render(writer, session)
+ return writer.to_string()
+ else:
+ return super(SlotMap.SlotInfo, self).do_render(session)
+
+ def do_get_items(self, session):
+ slot = self.slot.get(session)
+
+ return ((self.display_names[x], slot[x])
+ for x in slot if x in self.display_names)
+
+ def render_slot_info_url(self, session):
+ return self.page.get_update_url(session, (self,))
+
+ def render_slot_info_index(self, session):
+ return self.index.path
+
+ # XXX these should be item_title, etc.
+
+ def render_item_title(self, session, item):
+ return item[0]
+
+ def render_item_value(self, session, item):
+ return item[1]
+
+ def render_item_job_id(self, session, item):
+ #return item[0] == "jid" and "id='job_id'" or ""
+ return item[0] == "Job ID" and "id='job_id'" or ""
+
+ def render_item_row_class(self, session, item):
+ return item[0] == "jid" and "class='hidden_row'" or ""
Modified: mgmt/trunk/cumin/python/cumin/grid/slot.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/slot.strings 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/grid/slot.strings 2009-08-27 19:52:28 UTC (rev 3594)
@@ -1,4 +1,4 @@
-[SlotSet.sql]
+[SlotDataSet.sql]
select
s.id,
s.name,
@@ -13,41 +13,1242 @@
left outer join slot_stats as c on c.id = s.stats_curr_id
left outer join job as j on j.custom_id = s.job_id
{sql_where}
-{sql_orderby}
+{sql_order_by}
{sql_limit}
-[SlotSet.count_sql]
-select count(1)
-from (select distinct name from slot as s {sql_where}) as s
+[SlotDataSet.count_sql]
+select count(*)
+from slot as s
+{sql_where}
-[SlotStatSet.sql]
+[SlotSet.sql]
select
- sum(case when (activity = 'Idle') and (state = 'Unclaimed') then 1 else 0 end) as available,
- sum(1) as all
-from (select
+ s.id,
s.name,
- s.pool,
- s.qmf_update_time,
+ s.machine,
+ s.system,
+ s.job_id,
+ j.id as jid,
c.activity,
- c.state
+ c.state,
+ c.load_avg
from slot as s
-left outer join slot_stats as c on c.id = s.stats_curr_id) as s
+left outer join slot_stats as c on c.id = s.stats_curr_id
+left outer join job as j on j.custom_id = s.job_id
{sql_where}
+{sql_orderby}
+{sql_limit}
-[SlotStatSet.count_sql]
-1
+[SlotSet.count_sql]
+select count(*)
+from slot as s
+{sql_where}
[SlotStats.html]
<table class="twocol">
<tbody>
- <tr>
- <td>
- <h2>General</h2>
- {general}
- </td>
- <td>
- {chart}
- </td>
- </tr>
+ <tr>
+ <td>
+ <h2>General</h2>
+ {general}
+ </td>
+ <td>
+ {chart}
+ </td>
+ </tr>
</tbody>
</table>
+
+[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.notify = function(fullpage, size) {
+ slot_clip_size = size;
+ this.img_loaded(document.images[slot_current_id]);
+ }
+ 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 = vis.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);
+ }
+
+ this.get_index = function (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 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;
+ var branch = wooly.session.branch(src);
+ branch.zl = level;
+ branch.zx = slot_clip_left;
+ branch.zy = slot_clip_top;
+ src = branch.marshal();
+
+ src = cumin.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();
+ cumin.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 = vis.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
+ if ((slot_map_info.size == 0) || (slot_zoom == 0))
+ return 1;
+ 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";
+ }
+ }
+ $("slot_visualization").style.display = "block";
+ cumin.makeFullPageable($("slot_visualization"));
+ 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 = $(slot_info_id);
+ if (oInfo) {
+ oInfo.style.visibility = "hidden";
+ }
+ slot_last_index = -1;
+ }
+
+ function get_slot_info(rx, ry) {
+ var click_info = vis.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 = $(slot_info_id);
+ 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 refire_info() {
+ if (slot_last_index > -1) {
+ do_info_request(slot_last_index)
+ }
+ }
+
+ function do_info_request(index) {
+ var branch = wooly.session.branch(slot_info_url);
+ branch.session[slot_info_index] = index;
+ var newreq = branch.marshal();
+ wooly.setIntervalUpdate(newreq, got_slot_info, 0, {index: index});
+ }
+
+ function got_slot_info(xhtml, args) {
+ if (slot_last_index == -1) return;
+ var oInfo = $(slot_info_id);
+ 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 = $(slot_info_id);
+ if (oInfo) {
+ oInfo.click_index = args.index;
+ oInfo.for_jid = null;
+ if (for_jid) {
+ clicks.doClick(for_jid.x, for_jid.y);
+ return;
+ }
+
+ document.body.appendChild(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
+ // just under the clicked slot
+ var topUnder = (abs_pos.y + y) + Math.floor(slot_map_info.size * 1.5);
+ var top = topUnder;
+
+ // if off the bottom of the map
+ if (topUnder + 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);
+ }
+
+ // if off the top of the page
+ if (top < 0) {
+ // revert to under the item
+ top = topUnder;
+ }
+
+ 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();
+ clicks.click_when = d.getTime();
+ var rpos = get_relative_event_pos(e);
+ if (rpos) {
+ clicks.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 = vis.get_index(x, y);
+ var oInfo = $(slot_info_id);
+ 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;
+ }
+ }
+ }
+
+ 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();
+ clicks.doubleclick_when = now.getTime();
+ if (clicks.click_handle != null) {
+ clearTimeout(clicks.click_handle); // Clear pending Click
+ clicks.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};
+ }
+}
+
+[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; */
+ margin: 3em auto;
+ padding: 1em;
+ z-index:200;
+ text-align: center;
+ background-color: white;
+ overflow: hidden;
+ opacity: 0.5;
+ -moz-opacity: 0.5;
+ display: none;
+ border: 1px solid #000;
+}
+
+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;
+ display: none;
+ float: left;
+}
+
+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" class="fullpageable">
+ <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="{image_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>
+<div style="clear: left"><!-- --></div>
+{slot_info}
+<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 original_clip_size = slot_clip_size;
+ $('slot_visualization').onfullpage = function (width) { vis.notify(true, width); };
+ $('slot_visualization').onrestore = function () { vis.notify(false, original_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>
+
+[SlotInfo.css]
+div.slot_info {
+ position: absolute;
+ top: 0;
+ left: 0.5em;
+ visibility: hidden;
+ z-index: 301;
+}
+
+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 {item_row_class}>
+ <td class="slot_info_title">{item_title}</td>
+ <td {item_job_id} class="slot_info_value">{item_value}</td>
+</tr>
+
+[SlotLegend.css]
+div.slot_legend {
+ margin-top: 0.1em;
+}
+
+div.slot_legend h3 {
+ margin-top: 0;
+}
+
+div.slot_states, div.slot_activities {
+ float: left;
+ margin-left: 1.3em;
+}
+
+div.slot_states ul, div.slot_activities ul {
+ padding: 0;
+ margin: 0;
+ font-size: 0.8em;
+ list-style: none;
+}
+
+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>{item_initial}</span>
+
+ {item_title}
+</li>
+
+[SlotActivities.item_html]
+<li>
+ <img src="{item_href}" width="{item_size}" height="{item_size}" alt="{item_title}"/>
+
+ {item_title}
+</li>
Modified: mgmt/trunk/cumin/python/cumin/grid/submission.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/submission.py 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/grid/submission.py 2009-08-27 19:52:28 UTC (rev 3594)
@@ -101,7 +101,7 @@
class SubmissionView(CuminView):
def __init__(self, app, name, submission):
- super(SubmissionView, self).__init__(app, name)
+ super(SubmissionView, self).__init__(app, name, submission)
self.tabs = TabbedModeSet(app, "tabs")
self.add_child(self.tabs)
@@ -123,7 +123,7 @@
self.task = task
from scheduler import SchedulerSelectField # XXX
-
+
self.scheduler = SchedulerSelectField(app, "scheduler", self.pool)
self.add_field(self.scheduler)
Modified: mgmt/trunk/cumin/python/cumin/grid/submitter.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/submitter.py 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/grid/submitter.py 2009-08-27 19:52:28 UTC (rev 3594)
@@ -50,41 +50,36 @@
class SubmitterView(CuminView):
def __init__(self, app, name, submitter):
- super(SubmitterView, self).__init__(app, name)
+ super(SubmitterView, self).__init__(app, name, submitter)
self.tabs = TabbedModeSet(app, "tabs")
self.add_child(self.tabs)
- stats = SubmitterStats(app, "stats")
+ stats = SubmitterStats(app, "stats", submitter)
self.tabs.add_tab(stats)
submissions = SubmitterSubmissionSet(app, "submissions", submitter)
self.tabs.add_tab(submissions)
- details = CuminDetails(app, "details")
+ details = CuminDetails(app, "details", submitter)
self.tabs.add_tab(details)
class SubmitterStats(Widget):
- def __init__(self, app, name):
+ def __init__(self, app, name, submitter):
super(SubmitterStats, self).__init__(app, name)
- stats = StatSet(app, "general", "general")
+ stats = StatSet(app, "general", submitter, "general")
self.add_child(stats)
- chart = self.JobsChart(app, "jobs")
+ chart = self.JobsChart(app, "jobs", submitter)
+ chart.stats = ("RunningJobs", "IdleJobs", "HeldJobs")
self.add_child(chart)
def render_title(self, session):
return "Statistics"
class JobsChart(StatFlashChart):
- def __init__(self, app, name):
- super(SubmitterStats.JobsChart, self).__init__ \
- (app, name)
-
- self.stats = ("RunningJobs", "IdleJobs", "HeldJobs")
-
- def render_title(self, session, sched):
+ def render_title(self, session):
return "Jobs"
class SubmitterSubmissionSet(SubmissionSet):
Modified: mgmt/trunk/cumin/python/cumin/inventory/main.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/inventory/main.py 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/inventory/main.py 2009-08-27 19:52:28 UTC (rev 3594)
@@ -17,6 +17,9 @@
app.main_page.main.inventory = self.frame
app.main_page.main.add_tab(self.frame)
+ self.system_slots_page = SystemSlotMapPage(app, "systemslots.png")
+ app.add_page(self.system_slots_page)
+
module = InventoryModule()
class InventoryFrame(CuminFrame):
Modified: mgmt/trunk/cumin/python/cumin/inventory/system.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/inventory/system.py 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/inventory/system.py 2009-08-27 19:52:28 UTC (rev 3594)
@@ -6,8 +6,10 @@
from cumin.parameters import *
from cumin.formats import *
from cumin.util import *
-from cumin.grid.slot import SlotFrame
+from cumin.grid.slot import SlotFrame, SlotMap, SlotMapPage
+from wooly import Session
+
strings = StringCatalog(__file__)
class SystemSet(CuminTable, Form):
@@ -115,30 +117,28 @@
self.object = SystemParameter(app, "id")
self.add_parameter(self.object)
- self.view = SystemView(app, "view")
+ self.view = SystemView(app, "view", self.object)
self.add_mode(self.view)
self.slot = SlotFrame(app, "slot")
self.add_mode(self.slot)
-from cumin.visualizations import SlotMap
-
class SystemStats(Widget):
- def __init__(self, app, name):
+ def __init__(self, app, name, system):
super(SystemStats, self).__init__(app, name)
- self.add_child(StatSet(app, "stats", "general"))
+ self.add_child(StatSet(app, "stats", system, "general"))
- chart = StatFlashChart(app, "freemem")
+ chart = StatFlashChart(app, "freemem", system)
chart.stats = ("memFree",)
self.add_child(chart)
- chart = StatFlashChart(app, "loadavg")
+ chart = StatFlashChart(app, "loadavg", system)
chart.stats = ("loadAverage1Min",)
self.add_child(chart)
- vis = self.SystemSlotMap(app, "system_slot_map")
- self.add_child(vis)
+ slots = SystemSlotMap(app, "system_slot_map", system)
+ self.add_child(slots)
def render_title(self, session):
return "Statistics"
@@ -147,29 +147,18 @@
job = Identifiable("XXX")
return self.page.main.grid.pool.job.get_href(session, job, None)
- class SystemSlotMap(SlotMap):
- def get_title_name(self, session, sysimage):
- return sysimage.nodeName
-
- def render_slot_clip_size(self, session, *args):
- return 240
-
class SystemView(CuminView):
- def __init__(self, app, name):
- super(SystemView, self).__init__(app, name)
+ def __init__(self, app, name, system):
+ super(SystemView, self).__init__(app, name, system)
- summary = CuminSummary(app, "summary")
- self.add_child(summary)
+ self.tabs = TabbedModeSet(app, "tabs")
+ self.add_child(self.tabs)
- self.__tabs = TabbedModeSet(app, "tabs")
- self.add_child(self.__tabs)
+ self.tabs.add_tab(SystemStats(app, "stats", system))
+ self.tabs.add_tab(SystemSlotSet(app, "slots", system))
+ self.tabs.add_tab(SystemServices(app, "services", system))
+ self.tabs.add_tab(CuminDetails(app, "details", system))
- self.__tabs.add_tab(SystemStats(app, "stats"))
- #self.__tabs.add_tab(SystemJobSet(app, "jobs", submission))
- self.__tabs.add_tab(SystemSlotSet(app, "slots"))
- self.__tabs.add_tab(SystemServices(app, "services"))
- self.__tabs.add_tab(CuminDetails(app, "details"))
-
from cumin.grid.job import JobTab
class SystemJobSet(JobTab):
@@ -189,47 +178,41 @@
from cumin.grid.slot import SlotSet
class SystemSlotSet(SlotSet):
- def get_args(self, session):
- return self.frame.get_args(session)
+ def __init__(self, app, name, system):
+ super(SystemSlotSet, self).__init__(app, name)
- def render_title(self, session, *args):
- return "Grid Slots %s" % fmt_count(self.get_item_count(session, *args))
+ self.system = system
- def render_sql_where(self, session, system):
+ def render_title(self, session):
+ return "Grid Slots %s" % fmt_count(self.get_item_count(session))
+
+ def render_sql_where(self, session):
elems = list()
elems.append("system = %(nodeName)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, system):
+ def get_sql_values(self, session):
+ system = self.system.get(session)
return {"nodeName": system.nodeName}
-class SystemVisualization(SystemSlotSet):
- def __init__(self, vis, app, name):
- super(SystemVisualization, self).__init__(app, name)
- vis.add_visualization(self, name)
+class SystemServices(ItemSet):
+ def __init__(self, app, name, system):
+ super(SystemServices, self).__init__(app, name)
- def get_info(self, session, id):
- system = Sysimage.get(id)
- return self.get_items(session, system)
+ self.system = system
- def render_sql_limit(self, session, *args):
- pass
-
- def render_sql_orderby(self, session, *args):
- return "order by machine, name asc"
-
-class SystemServices(ItemSet):
- def render_title(self, session, *args):
+ def render_title(self, session):
return "Services"
- def get_args(self, session):
- return (self.frame.get_object(session),)
+ def do_get_items(self, session):
+ system = self.system.get(session)
- def do_get_items(self, session, system):
daemons = list()
daemon_types = [Scheduler, Collector, Negotiator]
sql = "system = '%s'" % system.nodeName
@@ -257,7 +240,7 @@
href = self.page.main.messaging.broker.get_href(session, reg)
return fmt_link(href, item.url)
else:
- pool = model.Pool.get(item.Pool)
+ pool = Pool(item.Pool)
self.page.main.grid.pool.object.set(session, pool)
#self.page.main.show_grid_tab(session)
daemon = Identifiable(item.id)
@@ -286,3 +269,43 @@
return "Broker"
else:
return "Daemon"
+
+class SystemSlotMap(SlotMap):
+ def __init__(self, app, name, system):
+ super(SystemSlotMap, self).__init__(app, name)
+
+ self.system = system
+ self.slot_clip_size = 240
+
+ def do_process(self, session):
+ super(SystemSlotMap, self).do_process(session)
+
+ system = self.system.get(session)
+
+ self.slots.add_where_expr(session, "s.system = '%s'", system.nodeName)
+
+ def render_image_href(self, session):
+ system = self.system.get(session)
+
+ import main # XXX
+
+ page = main.module.system_slots_page
+ sess = Session(page)
+
+ page.system.set(sess, system)
+
+ return sess.marshal()
+
+class SystemSlotMapPage(SlotMapPage):
+ def __init__(self, app, name):
+ super(SystemSlotMapPage, self).__init__(app, name)
+
+ self.system = SystemParameter(app, "id")
+ self.add_parameter(self.system)
+
+ def do_process(self, session):
+ super(SystemSlotMapPage, self).do_process(session)
+
+ system = self.system.get(session)
+
+ self.slots.add_where_expr(session, "s.system = '%s'", system.nodeName)
Modified: mgmt/trunk/cumin/python/cumin/inventory/system.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/inventory/system.strings 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/inventory/system.strings 2009-08-27 19:52:28 UTC (rev 3594)
@@ -53,6 +53,8 @@
<td>
<h2>Memory/Load</h2>
{stats}
+ <br/>
+ <h2>Grid Slots</h2>
{system_slot_map}
</td>
<td>
Modified: mgmt/trunk/cumin/python/cumin/main.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/main.py 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/main.py 2009-08-27 19:52:28 UTC (rev 3594)
@@ -5,7 +5,7 @@
from mint import *
from parsley.config import Config, ConfigParameter
from parsley.loggingex import *
-from stat import StatChartPage, StatStackedPage, SlotMapPage, \
+from stat import StatChartPage, StatStackedPage, \
StatFlashPage, FlashFullPage
from wooly import Application, Session, Page
from wooly.devel import DevelPage
@@ -63,7 +63,6 @@
self.add_page(CallPage(self, "call.xml"))
self.add_page(StatChartPage(self, "stats.png"))
self.add_page(StatStackedPage(self, "stacked.png"))
- self.add_page(SlotMapPage(self, "slots.png"))
self.add_page(StatFlashPage(self, "chart.json"))
self.add_page(FlashFullPage(self, "flashpage.html"))
Modified: mgmt/trunk/cumin/python/cumin/messaging/broker.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/messaging/broker.py 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/messaging/broker.py 2009-08-27 19:52:28 UTC (rev 3594)
@@ -149,21 +149,19 @@
class BrokerView(CuminView):
def __init__(self, app, name, vhost):
- super(BrokerView, self).__init__(app, name)
+ super(BrokerView, self).__init__(app, name, vhost)
- self.vhost = vhost
-
tabs = TabbedModeSet(app, "tabs")
self.add_child(tabs)
#tabs.add_tab(BrokerStats(app, "stats"))
- tabs.add_tab(self.BrokerQueueTab(app, "queues", self.vhost))
- tabs.add_tab(ExchangeSet(app, "exchanges", self.vhost))
- tabs.add_tab(ConnectionSet(app, "conns", self.vhost))
- tabs.add_tab(LinkSet(app, "links", self.vhost))
- tabs.add_tab(BrokerAccessControl(app, "access", self.vhost))
- tabs.add_tab(BrokerClustering(app, "cluster", self.vhost))
- tabs.add_tab(self.BrokerDetailsTab(app, "details", self.vhost))
+ tabs.add_tab(self.BrokerQueueTab(app, "queues", vhost))
+ tabs.add_tab(ExchangeSet(app, "exchanges", vhost))
+ tabs.add_tab(ConnectionSet(app, "conns", vhost))
+ tabs.add_tab(LinkSet(app, "links", vhost))
+ tabs.add_tab(BrokerAccessControl(app, "access", vhost))
+ tabs.add_tab(BrokerClustering(app, "cluster", vhost))
+ tabs.add_tab(self.BrokerDetailsTab(app, "details", vhost))
def render_group_links(self, session, object):
return "XXX"
@@ -203,41 +201,38 @@
def __init__(self, app, name, vhost):
super(BrokerView.BrokerDetailsTab, self).__init__(app, name)
- self.vhost = vhost
-
- props = self.Properties(app, "properties")
+ props = self.Properties(app, "properties", vhost)
self.add_child(props)
- actions = self.Actions(app, "actions")
- self.add_child(actions)
+ tasks = self.Tasks(app, "tasks", vhost)
+ self.add_child(tasks)
def render_title(self, session):
return "Details"
class Properties(CuminProperties):
- def do_get_items(self, session, object):
- broker = self.parent.vhost.get(session).broker
-
+ def do_get_items(self, session):
+ broker = self.object.get(session).broker
cls = self.app.model.get_class_by_object(broker)
- props = [(x.get_title(session),
- x.value(session, broker))
+
+ props = [(x.get_title(session), x.value(session, broker))
for x in cls.properties]
return props
- class Actions(CuminActions):
- def do_get_items(self, session, object):
- broker = self.parent.vhost.get(session).broker
-
+ class Tasks(CuminTasks):
+ def do_get_items(self, session):
+ broker = self.object.get(session).broker
cls = self.app.model.get_class_by_object(broker)
- acts = [(x.get_href(session, broker),
- x.get_title(session),
- x.get_enabled(session, broker))
- for x in cls.actions
- if x.navigable and not x.aggregate]
- return acts
+ tasks = [(x.get_href(session, broker),
+ x.get_title(session),
+ x.get_enabled(session, broker))
+ for x in cls.actions
+ if x.navigable and not x.aggregate]
+ return tasks
+
class ModuleNotEnabled(Widget):
def do_render(self, session):
return "This module is not enabled"
@@ -277,21 +272,12 @@
self.acl = acl
- props = self.Properties(app, "props")
- self.add_child(props)
+ self.props = CuminProperties(app, "props", self.acl)
+ self.add_child(self.props)
- stats = self.Stats(app, "stats", "general")
- self.add_child(stats)
+ self.stats = StatSet(app, "stats", self.acl, "general")
+ self.add_child(self.stats)
- # XXX don't do this this way
- class Properties(CuminProperties):
- def get_args(self, session):
- return (self.parent.acl.get(session),)
-
- class Stats(StatSet):
- def get_args(self, session):
- return (self.parent.acl.get(session),)
-
class BrokerClustering(ModeSet):
def __init__(self, app, name, vhost):
super(BrokerClustering, self).__init__(app, name)
@@ -301,11 +287,11 @@
self.cluster = self.ClusteringModuleAttribute(self, "cluster")
self.add_attribute(self.cluster)
- mode = ModuleNotEnabled(app, "notenabled")
- self.add_mode(mode)
+ self.notenabled = ModuleNotEnabled(app, "notenabled")
+ self.add_mode(self.notenabled)
- self.__view = BrokerClusteringView(app, "view", self.cluster)
- self.add_mode(self.__view)
+ self.view = BrokerClusteringView(app, "view", self.cluster)
+ self.add_mode(self.view)
class ClusteringModuleAttribute(Attribute):
def get_default(self, session):
@@ -316,7 +302,7 @@
def do_process(self, session):
if self.cluster.get(session):
- self.__view.show(session)
+ self.view.show(session)
def render_title(self, session):
return "Clustering"
@@ -325,22 +311,12 @@
def __init__(self, app, name, cluster):
super(BrokerClusteringView, self).__init__(app, name)
- self.cluster = cluster
-
- props = self.Properties(app, "props")
+ props = CuminProperties(app, "props", cluster)
self.add_child(props)
- stats = self.Stats(app, "stats", "general")
+ stats = StatSet(app, "stats", cluster, "general")
self.add_child(stats)
- class Properties(CuminProperties):
- def get_args(self, session):
- return (self.parent.cluster.get(session),)
-
- class Stats(StatSet):
- def get_args(self, session):
- return (self.parent.cluster.get(session),)
-
class BrokerStats(Widget):
def __init__(self, app, name):
super(BrokerStats, self).__init__(app, name)
@@ -578,54 +554,6 @@
def render_title(self, session):
return "Register New Brokers"
-class BrokerEdit(CuminFieldForm):
- def __init__(self, app, name):
- super(BrokerEdit, self).__init__(app, name)
-
- self.broker_name = UniqueNameField(app, "name", BrokerRegistration)
- self.add_field(self.broker_name)
-
- self.groups = BrokerGroupCheckboxField(app, "groups")
- self.add_field(self.groups)
-
- def init(self):
- super(BrokerEdit, self).init()
-
- self.broker_name.set_object_attr(self.frame.object)
-
- def get_args(self, session):
- return self.frame.get_args(session)
-
- def render_title(self, session, reg):
- return "Edit Broker '%s'" % reg.name
-
- def process_cancel(self, session, reg):
- branch = session.branch()
- self.frame.view.show(branch)
- self.page.set_redirect_url(session, branch.marshal())
-
- def process_submit(self, session, reg):
- errors = self.validate(session)
-
- if errors:
- pass
- else:
- action = self.app.model.management_server.edit
- args = {"name": self.broker_name.get(session)}
- action.invoke(reg, args)
-
- for group in self.groups.get(session):
- if group not in reg.groups:
- reg.addBrokerGroup(group)
-
- for group in reg.groups:
- if group not in self.groups.get(session):
- reg.removeBrokerGroup(group)
-
- reg.syncUpdate()
-
- self.process_cancel(session, reg)
-
def process_display(self, session, reg):
self.broker_name.set(session, reg.name)
Modified: mgmt/trunk/cumin/python/cumin/messaging/broker.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/messaging/broker.strings 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/messaging/broker.strings 2009-08-27 19:52:28 UTC (rev 3594)
@@ -28,8 +28,8 @@
{properties}
</td>
<td>
- <h2>Actions</h2>
- {actions}
+ <h2>Tasks</h2>
+ {tasks}
</td>
</tr>
</tbody>
Modified: mgmt/trunk/cumin/python/cumin/messaging/brokergroup.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/messaging/brokergroup.py 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/messaging/brokergroup.py 2009-08-27 19:52:28 UTC (rev 3594)
@@ -90,18 +90,17 @@
class BrokerGroupView(CuminView):
def __init__(self, app, name, group):
- super(BrokerGroupView, self).__init__(app, name)
+ super(BrokerGroupView, self).__init__(app, name, group)
- self.group = group
+ self.tabs = TabbedModeSet(app, "tabs")
+ self.add_child(self.tabs)
- self.__tabs = TabbedModeSet(app, "tabs")
- self.add_child(self.__tabs)
-
+ # XXX
brokers = BrokerSet(app, "brokers")
- brokers.group = self.group
- self.__tabs.add_tab(brokers)
+ brokers.group = group
+ self.tabs.add_tab(brokers)
- self.__tabs.add_tab(CuminDetails(app, "details"))
+ self.tabs.add_tab(CuminDetails(app, "details", group))
class BrokerGroupForm(CuminFieldForm):
def __init__(self, app, name, task):
Modified: mgmt/trunk/cumin/python/cumin/messaging/brokerlink.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/messaging/brokerlink.py 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/messaging/brokerlink.py 2009-08-27 19:52:28 UTC (rev 3594)
@@ -213,7 +213,7 @@
class LinkView(CuminView):
def __init__(self, app, name, link):
- super(LinkView, self).__init__(app, name)
+ super(LinkView, self).__init__(app, name, link)
self.tabs = TabbedModeSet(app, "tabs")
self.add_child(self.tabs)
@@ -223,16 +223,18 @@
self.routes = RouteSet(app, "routes", link)
self.tabs.add_tab(self.routes)
- self.tabs.add_tab(CuminDetails(app, "details"))
+ self.tabs.add_tab(CuminDetails(app, "details", link))
class LinkStats(TabbedModeSet):
- def __init__(self, app, name):
+ def __init__(self, app, name, link):
super(LinkStats, self).__init__(app, name)
- self.add_child(StatSet(app, "io", "io"))
- self.add_child(StatSet(app, "general", "general"))
+ self.add_child(StatSet(app, "io", link, "io"))
+ self.add_child(StatSet(app, "general", link, "general"))
- chart = self.ReceiveRouteDropRateChart(app, "recvroutedrop")
+ chart = self.ReceiveRouteDropRateChart(app, "recvroutedrop", link)
+ chart.stats = ("msgReceives", "msgRoutes", "msgDrops")
+ chart.mode = "rate"
self.add_child(chart)
chart = StatFlashChart(app, "producers")
@@ -243,16 +245,9 @@
return "Statistics"
class ReceiveRouteDropRateChart(StatFlashChart):
- def __init__(self, app, name):
- super(LinkStats.ReceiveRouteDropRateChart, self).__init__ \
- (app, name)
+ def render_title(self, session):
+ return "Messages received, routed, and dropped"
- self.stats = ("msgReceives", "msgRoutes", "msgDrops")
- self.mode = "rate"
-
- def render_title(self, session, exchange):
- return "Messages Received, Routed, and Dropped"
-
class ExchangeInputSet(RadioInputSet):
def __init__(self, app, name, state):
super(ExchangeInputSet, self).__init__(app, name, None)
Modified: mgmt/trunk/cumin/python/cumin/messaging/connection.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/messaging/connection.py 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/messaging/connection.py 2009-08-27 19:52:28 UTC (rev 3594)
@@ -161,40 +161,36 @@
class ConnectionView(CuminView):
def __init__(self, app, name, conn):
- super(ConnectionView, self).__init__(app, name)
+ super(ConnectionView, self).__init__(app, name, conn)
self.tabs = TabbedModeSet(app, "tabs")
self.add_child(self.tabs)
- self.tabs.add_tab(ConnectionStats(app, "stats"))
+ self.tabs.add_tab(ConnectionStats(app, "stats", conn))
self.sessions = SessionSet(app, "sessions", conn)
self.tabs.add_tab(self.sessions)
- self.tabs.add_tab(CuminDetails(app, "details"))
+ self.tabs.add_tab(CuminDetails(app, "details", conn))
class ConnectionStats(Widget):
- def __init__(self, app, name):
+ def __init__(self, app, name, conn):
super(ConnectionStats, self).__init__(app, name)
- self.add_child(StatSet(app, "io", "io"))
- self.add_child(StatSet(app, "general", "general"))
+ self.add_child(StatSet(app, "io", conn, "io"))
+ self.add_child(StatSet(app, "general", conn, "general"))
- chart = self.SendReceiveRateChart(app, "sendrecv")
+ chart = self.SendReceiveRateChart(app, "sendrecv", conn)
+ chart.stats = ("bytesFromClient", "bytesToClient")
+ chart.mode = "rate"
self.add_child(chart)
def render_title(self, session):
return "Statistics"
class SendReceiveRateChart(StatFlashChart):
- def __init__(self, app, name):
- super(ConnectionStats.SendReceiveRateChart, self).__init__(app, name)
-
- self.stats = ("bytesFromClient", "bytesToClient")
- self.mode = "rate"
-
def render_title(self, session, conn):
- return "Bytes Sent and Received"
+ return "Bytes sent and received"
class SessionSetTaskForm(CuminTaskForm):
def __init__(self, app, name, task):
Modified: mgmt/trunk/cumin/python/cumin/messaging/exchange.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/messaging/exchange.py 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/messaging/exchange.py 2009-08-27 19:52:28 UTC (rev 3594)
@@ -165,7 +165,7 @@
self.object = ExchangeParameter(app, "id")
self.add_parameter(self.object)
- self.view = ExchangeView(app, "view")
+ self.view = ExchangeView(app, "view", self.object)
self.add_mode(self.view)
def show_object(self, session, exchange):
@@ -175,14 +175,19 @@
return super(ExchangeFrame, self).show_object(session, exchange)
- def render_title(self, session, exchange):
- if exchange.name:
- return super(ExchangeFrame, self).render_title(session, exchange)
- else:
- return "Default Exchange"
+ def render_title(self, session):
+ exchange = self.object.get(session)
- def render_href(self, session, exchange):
if exchange:
+ if exchange.name:
+ return super(ExchangeFrame, self).render_title(session)
+ else:
+ return "Default exchange"
+
+ def render_href(self, session):
+ exchange = self.object.get(session)
+
+ if exchange:
return super(ExchangeFrame, self).render_href(session, exchange)
class ExchangeRemoveForm(CuminTaskForm):
@@ -202,39 +207,40 @@
self.add_parameter(self.object)
class ExchangeView(CuminView):
- def __init__(self, app, name):
- super(ExchangeView, self).__init__(app, name)
+ def __init__(self, app, name, exchange):
+ super(ExchangeView, self).__init__(app, name, exchange)
self.tabs = TabbedModeSet(app, "tabs")
self.add_child(self.tabs)
- self.tabs.add_tab(ExchangeStats(app, "stats"))
+ self.tabs.add_tab(ExchangeStats(app, "stats", exchange))
- self.bindings = ExchangeBindingSet(app, "bindings")
+ self.bindings = ExchangeBindingSet(app, "bindings", exchange)
self.tabs.add_tab(self.bindings)
- self.tabs.add_tab(CuminDetails(app, "details"))
+ self.tabs.add_tab(CuminDetails(app, "details", exchange))
class ExchangeBindingSet(BindingSet):
- def __init__(self, app, name):
+ def __init__(self, app, name, exchange):
super(ExchangeBindingSet, self).__init__(app, name)
+ self.exchange = exchange
+
self.set_default_column_name("q_id")
def get_visible_columns(self, session):
return self.get_request_visible_columns(session, ["q_id"])
def get_sql_values(self, session):
- exchange = self.frame.object.get(session)
+ exchange = self.exchange.get(session)
return {"id": exchange.id}
def render_title(self, session):
- exchange = self.frame.object.get(session)
- return "Queue Bindings %s" % \
- fmt_count(exchange.bindings.count())
+ exchange = self.exchange.get(session)
+ return "Queue Bindings %s" % fmt_count(exchange.bindings.count())
def render_sql_where(self, session):
- exchange = self.frame.object.get(session)
+ exchange = self.exchange.get(session)
elems = list()
elems.append("b.exchange_id = %(id)r")
elems.append(self.phase.get_sql_constraint(session, exchange))
@@ -391,16 +397,18 @@
return "<em>XML:</em> Route message to queues based on XML content of the message"
class ExchangeStats(Widget):
- def __init__(self, app, name):
+ def __init__(self, app, name, exchange):
super(ExchangeStats, self).__init__(app, name)
- self.add_child(StatSet(app, "io", "io"))
- self.add_child(StatSet(app, "general", "general"))
+ self.add_child(StatSet(app, "io", exchange, "io"))
+ self.add_child(StatSet(app, "general", exchange, "general"))
- chart = self.ReceiveRouteDropRateChart(app, "recvroutedrop")
+ chart = self.ReceiveRouteDropRateChart(app, "recvroutedrop", exchange)
+ chart.stats = ("msgReceives", "msgRoutes", "msgDrops")
+ chart.mode = "rate"
self.add_child(chart)
- chart = StatFlashChart(app, "producers")
+ chart = StatFlashChart(app, "producers", exchange)
chart.stats = ("producerCount",)
self.add_child(chart)
@@ -408,16 +416,9 @@
return "Statistics"
class ReceiveRouteDropRateChart(StatFlashChart):
- def __init__(self, app, name):
- super(ExchangeStats.ReceiveRouteDropRateChart, self).__init__ \
- (app, name)
+ def render_title(self, session):
+ return "Messages received, routed, and dropped"
- self.stats = ("msgReceives", "msgRoutes", "msgDrops")
- self.mode = "rate"
-
- def render_title(self, session, exchange):
- return "Messages Received, Routed, and Dropped"
-
class ExchangeInfo(object):
@classmethod
def is_builtin(cls, exchange):
Modified: mgmt/trunk/cumin/python/cumin/messaging/queue.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/messaging/queue.py 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/messaging/queue.py 2009-08-27 19:52:28 UTC (rev 3594)
@@ -210,12 +210,12 @@
class QueueView(CuminView):
def __init__(self, app, name, queue):
- super(QueueView, self).__init__(app, name)
+ super(QueueView, self).__init__(app, name, queue)
self.tabs = TabbedModeSet(app, "tabs")
self.add_child(self.tabs)
- self.tabs.add_tab(QueueStats(app, "stats"))
+ self.tabs.add_tab(QueueStats(app, "stats", queue))
self.bindings = QueueBindingSet(app, "bindings", queue)
self.tabs.add_tab(self.bindings)
@@ -573,32 +573,31 @@
self.add_parameter(self.object)
class BindSummaryPropertiesField(FormField):
- def __init__(self, app, name):
+ def __init__(self, app, name, queue):
super(BindSummaryPropertiesField, self).__init__(app, name)
- self.sum_props = self.SummaryProperties(app, "properties")
+ self.sum_props = self.SummaryProperties(app, "properties", queue)
self.add_child(self.sum_props)
self.prop_tmpl = Template(self, "properties_html")
class SummaryProperties(CuminProperties):
- def do_get_items(self, session, queue):
+ def do_get_items(self, session):
+ queue = self.object.get(session)
+
return [("Name", queue.name),
("Durable", queue.durable),
("Exclusive", queue.exclusive),
("Auto-Delete", queue.autoDelete)]
- def render_inputs(self, session, *args):
+ def render_inputs(self, session):
writer = Writer()
- self.prop_tmpl.render(writer, session, args)
+ self.prop_tmpl.render(writer, session)
return writer.to_string()
- def render_prop_items(self, session, args):
- return self.sum_props.render_items(session, *args)
+ def render_prop_items(self, session):
+ return self.sum_props.render_items(session)
- def get_args(self, session):
- return (self.form.queue.get(session),)
-
class BindingAddForm(CuminFieldForm):
def __init__(self, app, name, task):
super(BindingAddForm, self).__init__(app, name)
@@ -611,7 +610,7 @@
self.vhost = self.VhostAttribute(app, "vhost")
self.add_attribute(self.vhost)
- self.props = BindSummaryPropertiesField(app, "props")
+ self.props = BindSummaryPropertiesField(app, "props", self.queue)
self.add_field(self.props)
self.bindings = self.ExchangeBindings(app, "bindings", self.vhost)
@@ -654,30 +653,33 @@
self.add_parameter(self.object)
class QueueStats(RadioModeSet):
- def __init__(self, app, name):
+ def __init__(self, app, name, queue):
super(QueueStats, self).__init__(app, name)
- self.add_tab(QueueStatsGeneral(app, "gen"))
- self.add_tab(QueueStatsDurability(app, "dur"))
- self.add_tab(QueueStatsTransactions(app, "txn"))
+ self.add_tab(QueueStatsGeneral(app, "gen", queue))
+ self.add_tab(QueueStatsDurability(app, "dur", queue))
+ self.add_tab(QueueStatsTransactions(app, "txn", queue))
def render_title(self, session):
return "Statistics"
class QueueStatsGeneral(Widget):
- def __init__(self, app, name):
+ def __init__(self, app, name, queue):
super(QueueStatsGeneral, self).__init__(app, name)
- self.add_child(StatSet(app, "general", "general"))
- self.add_child(StatSet(app, "io", "io"))
+ self.add_child(StatSet(app, "general", queue, "general"))
+ self.add_child(StatSet(app, "io", queue, "io"))
- chart = self.EnqueueDequeueRateChart(app, "enqdeq")
+ chart = self.EnqueueDequeueRateChart(app, "enqdeq", queue)
+ chart.stats = ("msgTotalEnqueues", "msgTotalDequeues")
+ chart.mode = "rate"
self.add_child(chart)
- chart = self.DepthChart(app, "depth")
+ chart = self.DepthChart(app, "depth", queue)
+ chart.stats = ("msgDepth",)
self.add_child(chart)
- chart = StatFlashChart(app, "consumers")
+ chart = StatFlashChart(app, "consumers", queue)
chart.stats = ("consumerCount",)
self.add_child(chart)
@@ -685,123 +687,96 @@
return "General"
class EnqueueDequeueRateChart(StatFlashChart):
- def __init__(self, app, name):
- super(QueueStatsGeneral.EnqueueDequeueRateChart,
- self).__init__(app, name)
+ def render_title(self, session):
+ return "Messages enqueued and dequeued"
- self.stats = ("msgTotalEnqueues", "msgTotalDequeues")
- self.mode = "rate"
-
- def render_title(self, session, queue):
- return "Messages Enqueued and Dequeued"
-
class DepthChart(StatFlashChart):
- def __init__(self, app, name):
- super(QueueStatsGeneral.DepthChart, self).__init__(app, name)
-
- self.stats = ("msgDepth",)
-
- def render_title(self, session, queue):
+ def render_title(self, session):
return "Queue Depth"
class QueueStatsDurability(Widget):
- def __init__(self, app, name):
+ def __init__(self, app, name, queue):
super(QueueStatsDurability, self).__init__(app, name)
- self.add_child(StatSet(app, "io", "io.durable"))
- self.add_child(JournalStats(app, "jrnl", "io.journal"))
+ self.add_child(StatSet(app, "io", queue, "io.durable"))
+ self.add_child(JournalStats(app, "jrnl", queue, "io.journal"))
- chart = self.EnqueueDequeueRateChart(app, "enqdeq")
+ chart = self.EnqueueDequeueRateChart(app, "enqdeq", queue)
+ chart.stats = ("msgPersistEnqueues", "msgPersistDequeues")
+ chart.mode = "rate"
self.add_child(chart)
def render_title(self, session):
return "Durability"
class EnqueueDequeueRateChart(StatFlashChart):
- def __init__(self, app, name):
- super(QueueStatsDurability.EnqueueDequeueRateChart,
- self).__init__(app, name)
-
- self.stats = ("msgPersistEnqueues", "msgPersistDequeues")
- self.mode = "rate"
-
def render_title(self, session, queue):
- return "Durable Messages Enqueued and Dequeued"
+ return "Durable messages enqueued and eequeued"
class JournalStats(StatSet):
- def get_args(self, session):
- queue = self.frame.get_args(session)[0]
+ def __init__(self, app, name, queue, category):
+ super(JournalStats, self).__init__(app, name, queue, category)
- try:
- jrnl = Journal.selectBy(queue=queue)[0]
- except IndexError:
- jrnl = None
+ self.journal = self.JournalAttribute(app, "journal")
+ self.add_attribute(self.journal)
- return (jrnl,)
+ class JournalAttribute(Attribute):
+ def get(self, session):
+ queue = self.widget.object.get(session)
- def render_title(self, session, jrnl):
+ for journal in Journal.selectBy(queue=queue):
+ return journal
+
+ def render_title(self, session):
return "Journal"
- def do_render(self, session, jrnl):
- if jrnl:
- return super(JournalStats, self).do_render(session, jrnl)
+ def do_render(self, session):
+ journal = self.journal.get(session)
+
+ if journal:
+ return super(JournalStats, self).do_render(session)
else:
return "<div class=\"iblock\">%s</div>" % fmt_none()
class QueueStatsTransactions(Widget):
- def __init__(self, app, name):
+ def __init__(self, app, name, queue):
super(QueueStatsTransactions, self).__init__(app, name)
- self.add_child(StatSet(app, "transactions", "txn"))
- self.add_child(StatSet(app, "io", "io.txn"))
+ self.add_child(StatSet(app, "transactions", queue, "txn"))
+ self.add_child(StatSet(app, "io", queue, "io.txn"))
- chart = self.EnqueueTransactionRateChart(app, "enqtxn")
+ chart = self.EnqueueTransactionRateChart(app, "enqtxn", queue)
+ chart.stats = ("enqueueTxnStarts", "enqueueTxnCommits",
+ "enqueueTxnRejects")
+ chart.mode = "rate"
self.add_child(chart)
- chart = self.DequeueTransactionRateChart(app, "deqtxn")
+ chart = self.DequeueTransactionRateChart(app, "deqtxn", queue)
+ chart.stats = ("dequeueTxnStarts", "dequeueTxnCommits",
+ "dequeueTxnRejects")
+ chart.mode = "rate"
self.add_child(chart)
- chart = self.EnqueueDequeueRateChart(app, "enqdeq")
+ chart = self.EnqueueDequeueRateChart(app, "enqdeq", queue)
+ chart.stats = ("msgTxnEnqueues", "msgTxnDequeues")
+ chart.mode = "rate"
self.add_child(chart)
def render_title(self, session):
return "Transactions"
class EnqueueTransactionRateChart(StatFlashChart):
- def __init__(self, app, name):
- super(QueueStatsTransactions.EnqueueTransactionRateChart,
- self).__init__(app, name)
+ def render_title(self, session):
+ return "Enqueue transaction operations per second"
- self.stats = ("enqueueTxnStarts", "enqueueTxnCommits",
- "enqueueTxnRejects")
- self.mode = "rate"
-
- def render_title(self, session, queue):
- return "Enqueue Transaction Operations per Second"
-
class DequeueTransactionRateChart(StatFlashChart):
- def __init__(self, app, name):
- super(QueueStatsTransactions.DequeueTransactionRateChart,
- self).__init__(app, name)
+ def render_title(self, session):
+ return "Dequeue transaction operations per second"
- self.stats = ("dequeueTxnStarts", "dequeueTxnCommits",
- "dequeueTxnRejects")
- self.mode = "rate"
-
- def render_title(self, session, queue):
- return "Dequeue Transaction Operations per Second"
-
class EnqueueDequeueRateChart(StatFlashChart):
- def __init__(self, app, name):
- super(QueueStatsTransactions.EnqueueDequeueRateChart,
- self).__init__(app, name)
+ def render_title(self, session):
+ return "Transactional messages enqueued and dequeued"
- self.stats = ("msgTxnEnqueues", "msgTxnDequeues")
- self.mode = "rate"
-
- def render_title(self, session, queue):
- return "Transactional Messages Enqueued and Dequeued"
-
class QueueSelectField(FormField):
def __init__(self, app, name, form):
super(QueueSelectField, self).__init__(app, name)
@@ -823,7 +798,7 @@
class QueueInputSet(RadioInputSet):
def do_get_items(self, session):
- queue = self.form.queue.get(session)
+ queue = self.form.queue.get(session) # XXX
queue_list_full = sorted_by(list(queue.vhost.queues))
delta = timedelta(minutes=10)
queue_list = []
Modified: mgmt/trunk/cumin/python/cumin/model.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/model.py 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/model.py 2009-08-27 19:52:28 UTC (rev 3594)
@@ -4,7 +4,7 @@
from mint import Mint, MintConfig
from struct import unpack, calcsize
from sqlobject import sqlhub
-from sqlobject.sqlbuilder import Select
+from threading import Thread, Lock
from types import *
from wooly import *
from wooly.parameters import *
@@ -29,6 +29,8 @@
self.mint.pollEnabled = False
self.mint.expireEnabled = False
+ self.lock = Lock()
+
self.classes = list()
self.invocations = set()
@@ -37,6 +39,9 @@
self.tasks = list()
self.task_invocations = list()
+ self.limits_by_negotiator = dict()
+ self.jobs_by_submission = dict()
+
# Messaging
CuminBroker(self)
@@ -95,6 +100,9 @@
def stop(self):
self.mint.stop()
+ def get_sql_connection(self):
+ return sqlhub.getConnection().getConnection()
+
def add_class(self, cls):
self.classes.append(cls)
setattr(self, cls.cumin_name, cls)
@@ -107,32 +115,6 @@
if cls.mint_class is mint_object.__class__:
return cls
- def count_invocations(self, status):
- count = 0
-
- for invoc in self.invocations:
- if invoc.status == status:
- count += 1
-
- return count
-
- def write_xml(self, session, writer, objects):
- writer.write("<model>")
-
- pcount = self.count_invocations("pending")
- ccount = self.count_invocations("OK")
- fcount = len(self.invocations) - pcount - ccount
-
- writer.write("<invocations pending=\"%i\" " % pcount +
- "completed=\"%i\" " % ccount +
- "failed=\"%i\"/>" % fcount)
-
- for object in objects:
- cls = self.get_class_by_object(object)
- cls.write_xml(session, writer, object)
-
- writer.write("</model>")
-
def show_main(self, session):
return self.app.main_page.main.show(session)
@@ -147,6 +129,42 @@
return broker.getAmqpSession()
+ def get_negotiator_limits(self, negotiator):
+ self.lock.acquire()
+
+ try:
+ try:
+ store = self.limits_by_negotiator[negotiator]
+ except KeyError:
+ store = NegotiatorLimitStore(self, negotiator)
+ store.start_updates()
+
+ self.app.model.limits_by_negotiator[negotiator] = store
+
+ sleep(1)
+
+ return store.data
+ finally:
+ self.lock.release()
+
+ def get_submission_jobs(self, submission):
+ self.lock.acquire()
+
+ try:
+ try:
+ store = self.jobs_by_submission[submission]
+ except KeyError:
+ store = SubmissionJobStore(self, submission)
+ store.start_updates()
+
+ self.app.model.jobs_by_submission[submission] = store
+
+ sleep(1)
+
+ return store.data
+ finally:
+ self.lock.release()
+
class Task(object):
def __init__(self, app, cls):
self.app = app
@@ -586,7 +604,7 @@
return stats[0].qmfUpdateTime
def get_connection(self):
- return sqlhub.getConnection().getConnection()
+ return self.model.get_sql_connection()
def get_db_name(self):
name = self.name
@@ -1753,22 +1771,6 @@
def get_icon_href(self, session):
return "resource?name=group-36.png"
-class Pool(object):
- def __init__(self, collector):
- assert collector
-
- self.collector = collector
- self.id = self.collector.Pool
- self.name = self.collector.Name
-
- def get(cls, id):
- for coll in Collector.select("pool='%s'" % id):
- return Pool(coll)
- get = classmethod(get)
-
- def sync(self):
- pass
-
class CuminPool(CuminClass):
def __init__(self, model):
super(CuminPool, self).__init__(model, "pool", Pool)
@@ -1785,8 +1787,14 @@
def get_title(self, session):
return "Pool"
+ def get_object_name(self, pool):
+ coll = pool.get_collector()
+ return coll.Name
+
def get_object_title(self, session, pool):
- if pool.name == "main":
+ coll = pool.get_collector()
+
+ if coll.Name == "main":
title = "Main Pool"
else:
title = super(CuminPool, self).get_object_title(session, pool)
@@ -1810,7 +1818,7 @@
class CuminLimit(CuminClass):
def __init__(self, model):
super(CuminLimit, self).__init__ \
- (model, "limit", Limit)
+ (model, "limit", None)
prop = CuminProperty(self, "name")
prop.title = "Name"
@@ -1823,14 +1831,6 @@
prop.summary = True
prop.title = "Maximum"
- action = self.Edit(self, "edit")
- action.title = "Edit"
- action.summary = True
-
- action = self.SetLimit(self, "setlimit")
- action.navigable = False
- action.title = "Set Limit"
-
def init(self):
super(CuminLimit, self).init()
@@ -1841,28 +1841,8 @@
def get_object_title(self, session, limit):
title = self.get_title(session)
- name = limit.id
- return "%s '%s'" % (title, name)
+ return "%s '%s'" % (title, limit)
- class Edit(CuminAction):
- def show(self, session, limit):
- frame = self.cumin_class.show_object(session, limit)
- frame = frame.edit.show(session)
- return frame
-
- class SetLimit(CuminAction):
- def show(self, session, job):
- pass
-
- def get_title(self, session):
- return "Set Limit for"
-
- def do_invoke(self, limit, negotiator, completion):
- Name = limit.id
- Max = limit.max
- negotiator.SetLimit(self.mint.model, completion, Name, Max)
- #negotiator.SetLimit(self.mint.model, completion, Name, str(Max))
-
class CuminJobGroup(CuminClass):
def __init__(self, model):
super(CuminJobGroup, self).__init__ \
@@ -1886,7 +1866,8 @@
def init(self):
super(CuminJobGroup, self).init()
- self.frame = self.model.frame.grid.pool.job_group
+ # XXX
+ #self.frame = self.model.frame.grid.pool.job_group
def get_object_title(self, session, group):
title = self.get_title(session)
@@ -1901,9 +1882,9 @@
class Job(object):
def __init__(self, id):
-
real_id = id
sched, sep, jid = id.partition('#')
+
if jid:
real_id, sep, proc = jid.partition('#')
@@ -2129,6 +2110,7 @@
return "%s%s" % (conf, rect)
+# XXX no, not this way
class QMFCaller(object):
def __init__(self, default):
self.data = default
@@ -2198,9 +2180,6 @@
action = GetStartedAction(self, "GetStarted")
action.navigable = False
- action = self.GetJobs(self, "GetJobs")
- action.navigable = False
-
action = self.GetAd(self, "GetAd")
action.navigable = False
@@ -2237,16 +2216,6 @@
return qmf.data['JobAd']
- class GetJobs(CuminAction):
- def qmfcall(self, scheduler, submission):
-
- default = {'Jobs': {}}
- qmf = QMFCaller(default)
- scheduler.GetJobs(self.mint.model, qmf.get_completion(), submission, None)
- wait(qmf.done, timeout=5)
-
- return qmf.data['Jobs']
-
class CuminSubmission(RemoteClass):
def __init__(self, model):
super(CuminSubmission, self).__init__(model, "submission",
@@ -2393,9 +2362,6 @@
stat.title = "Resident Set Size"
stat.category = "general"
- action = self.GetLimits(self, "GetLimits")
- action.navigable = False
-
action = GetStartedAction(self, "GetStarted")
action.navigable = False
@@ -2450,17 +2416,6 @@
return [(group, call.data, (call.status, call.error, call.got_data))
for call, group in zip(calls, groups)]
- class GetLimits(CuminAction):
- def do_invoke(self, negotiator):
- default = {'Limits': {}}
- qmf = QMFCaller(default)
- negotiator.GetLimits(self.mint.model, qmf.get_completion(), None)
- wait(qmf.done, timeout=2)
-
- if not qmf.got_data:
- return {'timeout': True}
- return qmf.data['Limits']
-
class CuminSubject(CuminClass):
def __init__(self, model):
super(CuminSubject, self).__init__(model, "subject", Subject)
@@ -2468,16 +2423,95 @@
def get_title(self, session):
return "Subject"
-class JobGroup(object):
+class Pool(object):
def __init__(self, id):
self.id = id
- def get_id(self):
- return self.id
+ def get_collector(self):
+ for collector in Collector.selectBy(Pool=self.id):
+ return collector
-class Limit(object):
+ def get_grid(self):
+ for grid in Grid.selectBy(Pool=self.id):
+ return grid
+
+ def get_negotiator(self):
+ for negotiator in Negotiator.selectBy(Pool=self.id):
+ return negotiator
+
+class JobGroup(object):
def __init__(self, id):
self.id = id
def get_id(self):
return self.id
+
+class ObjectStore(object):
+ def __init__(self, model):
+ self.model = model
+ self.data = None
+
+ self.update_thread = self.UpdateThread(self)
+
+ def start_updates(self):
+ self.update_thread.start()
+
+ def update(self):
+ pass
+
+ def delete(self):
+ pass
+
+ class UpdateThread(Thread):
+ def __init__(self, store):
+ Thread.__init__(self)
+
+ self.store = store
+ self.setDaemon(True)
+
+ def run(self):
+ for i in range(20):
+ try:
+ self.store.update()
+ except Exception, e:
+ log.exception(e)
+
+ sleep(30)
+
+ self.store.delete()
+
+class UpdateTimedOut(Exception):
+ pass
+
+class NegotiatorLimitStore(ObjectStore):
+ def __init__(self, model, negotiator):
+ super(NegotiatorLimitStore, self).__init__(model)
+
+ self.negotiator = negotiator
+
+ def update(self):
+ def completion(status, data):
+ self.data = data["Limits"]
+
+ self.negotiator.GetLimits(self.model.mint.model, completion, None)
+
+ def delete(self):
+ del self.model.limits_by_negotiator[self.negotiator]
+
+class SubmissionJobStore(ObjectStore):
+ def __init__(self, model, submission):
+ super(SubmissionJobStore, self).__init__(model)
+
+ self.submission = submission
+
+ def update(self):
+ def completion(status, data):
+ self.data = data["Jobs"]
+
+ scheduler = self.submission.scheduler
+
+ scheduler.GetJobs \
+ (self.model.mint.model, completion, self.submission.Name, None)
+
+ def delete(self):
+ del self.model.jobs_by_submission[self.submission]
Modified: mgmt/trunk/cumin/python/cumin/parameters.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/parameters.py 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/parameters.py 2009-08-27 19:52:28 UTC (rev 3594)
@@ -1,7 +1,9 @@
from wooly import *
from mint import *
-import model
+from model import Pool
+from model import Job
+
class CuminObjectParameter(Parameter):
def __init__(self, app, name, cumin_class):
self.cumin_class = cumin_class
@@ -78,7 +80,7 @@
class JobParameter(Parameter):
def do_unmarshal(self, string):
- return model.Job(string)
+ return Job(string)
def do_marshal(self, job):
if isinstance(job, basestring):
@@ -102,27 +104,39 @@
class PeerParameter(LinkParameter):
pass
-class LimitParameter(Parameter):
- def do_unmarshal(self, string):
- return Limit(string)
-
- def do_marshal(self, limit):
- return limit.id
-
# XXX marked for death
class PeerParameter(LinkParameter):
pass
class PoolParameter(Parameter):
def do_unmarshal(self, string):
- for coll in Collector.selectBy(Pool=string):
- break
+ return Pool(string)
- return model.Pool(coll)
-
def do_marshal(self, pool):
return str(pool.id)
+class PoolAssociateAttribute(Attribute):
+ def __init__(self, app, name, pool):
+ super(PoolAssociateAttribute, self).__init__(app, name)
+
+ self.pool = pool
+
+ def get(self, session):
+ pool = self.pool.get(session)
+ return self.get_associate(session, pool)
+
+class PoolCollectorAttribute(PoolAssociateAttribute):
+ def get_associate(self, session, pool):
+ return pool.get_collector()
+
+class PoolGridAttribute(PoolAssociateAttribute):
+ def get_associate(self, session, pool):
+ return pool.get_grid()
+
+class PoolNegotiatorAttribute(PoolAssociateAttribute):
+ def get_associate(self, session, pool):
+ return pool.get_negotiator()
+
class QueueParameter(Parameter):
def do_unmarshal(self, string):
return Queue.get(int(string))
Modified: mgmt/trunk/cumin/python/cumin/stat.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/stat.py 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/stat.py 2009-08-27 19:52:28 UTC (rev 3594)
@@ -13,8 +13,6 @@
from OpenFlashChart import Chart, Element
-from visualizations import CuminVisualization
-
strings = StringCatalog(__file__)
class StatSet(ItemSet):
@@ -22,42 +20,32 @@
unit_abbrevs["message"] = "msg"
unit_abbrevs["transaction"] = "trans"
- def __init__(self, app, name, category):
+ def __init__(self, app, name, object, category):
super(StatSet, self).__init__(app, name)
+ self.object = object
self.category = category
self.update_enabled = True
- self.object = Attribute(app, "object");
- self.add_attribute(self.object);
+ def render_rate_text(self, session):
+ return "Per Second"
- def get_args(self, session):
- return self.frame.get_args(session)
-
- def do_get_items(self, session, object):
- stats = list()
+ def do_get_items(self, session):
+ object = self.object.get(session)
cls = self.app.model.get_class_by_object(object)
+ stats = list()
- for stat in cls.stats:
- if self.category == stat.category:
- stats.append((stat, object))
+ return [x for x in cls.stats if x.category == self.category]
- return stats
-
- def render_item_title(self, session, args):
- stat, object = args
+ def render_item_title(self, session, stat):
return stat.title
- def render_rate_text(self, session, args):
- return "Per Second"
-
- def render_item_name(self, session, args):
- stat, object = args
+ def render_item_name(self, session, stat):
return stat.name
- def render_item_value(self, session, args):
- stat, object = args
+ def render_item_value(self, session, stat):
+ object = self.object.get(session)
#if stat.link_cb:
# branch = session.branch()
@@ -67,8 +55,8 @@
return stat.value_html(object)
- def render_item_rate(self, session, args):
- stat, object = args
+ def render_item_rate(self, session, stat):
+ object = self.object.get(session)
#if False and stat.highlow: #XXX
# return "<small>high</small> <span>%i</span> " + \
@@ -94,9 +82,11 @@
return {'state': state}
class StatValueChart(Widget):
- def __init__(self, app, name):
+ def __init__(self, app, name, object):
super(StatValueChart, self).__init__(app, name)
+ self.object = object
+
self.mode = None
self.stats = ()
self.chart_type = None
@@ -108,10 +98,8 @@
self.fullpageable = True
- def get_args(self, session):
- return self.frame.get_args(session)
-
- def get_href_params(self, session, object):
+ def get_href_params(self, session):
+ object = self.object.get(session)
params = list()
cls = self.app.model.get_class_by_object(object).cumin_name
@@ -131,37 +119,42 @@
return params
- def render_href(self, session, object):
- params = self.get_href_params(session, object)
+ def render_href(self, session):
+ params = self.get_href_params(session)
return "%s?" % self.get_chart_name(session) + ";".join(params)
def get_chart_name(self, session):
return "stats.png"
- def render_fullpageable(self, session, object):
+ def render_fullpageable(self, session):
return self.fullpageable and " fullpageable" or ""
- def render_title(self, session, object):
+ def render_title(self, session):
+ object = self.object.get(session)
cls = self.app.model.get_class_by_object(object)
return getattr(cls, self.stats[0]).title
- def render_stats(self, session, object):
+ def render_stats(self, session):
+ object = self.object.get(session)
+ cls = self.app.model.get_class_by_object(object)
+
writer = Writer()
for name in self.stats:
- cls = self.app.model.get_class_by_object(object)
stat = getattr(cls, name)
- self.stats_tmpl.render(writer, session, stat, object)
+ self.stats_tmpl.render(writer, session, stat)
return writer.to_string()
- def render_stat_mode(self, session, stat, object):
+ def render_stat_mode(self, session, stat):
return self.mode
- def render_stat_color(self, session, stat, object):
+ def render_stat_color(self, session, stat):
return "rgb(255,0,0)"
- def render_stat_value(self, session, stat, object):
+ def render_stat_value(self, session, stat):
+ object = self.object.get(session)
+
if self.mode == "rate":
html = stat.rate_html(object)
else:
@@ -169,13 +162,13 @@
return html
- def render_stat_name(self, session, stat, object):
+ def render_stat_name(self, session, stat):
return stat.name
- def render_width(self, session, *args):
+ def render_width(self, session):
return 360
- def render_height(self, session, *args):
+ def render_height(self, session):
return 100
class StatStackedChart(StatValueChart):
@@ -188,34 +181,34 @@
def get_chart_name(self, session):
return "stacked.png"
- def render_height(self, session, object):
+ def render_height(self, session):
return 200
class StatFlashChart(StatValueChart):
def get_flash_name(self, session):
return "chart.json"
- def render_img_href(self, session, object):
- return super(StatFlashChart, self).render_href(session, object)
+ def render_img_href(self, session):
+ return super(StatFlashChart, self).render_href(session)
- def render_img_width(self, session, object):
- return super(StatFlashChart, self).render_width(session, object)
+ def render_img_width(self, session):
+ return super(StatFlashChart, self).render_width(session)
- def render_img_height(self, session, object):
- return super(StatFlashChart, self).render_height(session, object)
+ def render_img_height(self, session):
+ return super(StatFlashChart, self).render_height(session)
- def render_href(self, session, object):
- params = self.get_href_params(session, object)
+ def render_href(self, session):
+ params = self.get_href_params(session)
return escape_entity("%s?" % self.get_flash_name(session) + ";".join(params))
- def render_fullpage_href(self, session, object):
- params = self.get_href_params(session, object)
+ def render_fullpage_href(self, session):
+ params = self.get_href_params(session)
return "flashpage.html?" + ";".join(params)
- def render_width(self, session, *args):
+ def render_width(self, session):
return 360
- def render_height(self, session, *args):
+ def render_height(self, session):
return 120
class ImageCache(object):
@@ -255,121 +248,12 @@
self.__files[name] = {"time": datetime.now(), "file": file, "cookie": args}
return file
-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),
- "Retiring": (.8,.2,.8),
- None: (.8,.8,.8)}
-
- max_width = 400
- max_png_age = 30
- def __init__(self, app, name):
- super(SlotMapPage, self).__init__(app, name)
-
- self.vis = CuminVisualization(app)
-
- self.class_ = Parameter(app, "class")
- self.add_parameter(self.class_)
-
- self.id = IntegerParameter(app, "id")
- self.add_parameter(self.id)
-
- self.zoom_level = IntegerParameter(app, "zl")
- self.add_parameter(self.zoom_level)
-
- self.zoom_x = IntegerParameter(app, "zx")
- self.add_parameter(self.zoom_x)
-
- self.zoom_y = IntegerParameter(app, "zy")
- self.add_parameter(self.zoom_y)
-
- self.dot = Parameter(app, "dot")
- self.add_parameter(self.dot)
-
- self.cache = ImageCache()
-
- def get_content_type(self, session):
- return "image/png"
-
- def get_cache_control(self, session):
- return "no-cache"
-
- def get_args(self, session):
- name = self.class_.get(session)
- if name:
- id = self.id.get(session)
- return (self.vis.get_itemset_by_name(name),)
- 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 do_render(self, session, object):
- dot = self.dot.get(session)
- if dot:
- return self.render_dot(session, dot)
-
- zl = self.zoom_level.get(session)
- zx = self.zoom_x.get(session)
- zy = self.zoom_y.get(session)
-
- # determine if cached copy is recent enough
- cached_png, args = self.get_cached(session, zl)
- if cached_png:
- self.set_cookie(session, args)
- return cached_png
-
- map = HeatMapChart(self.max_width, self.max_width)
-
- slot_info = object.get_info(session, self.id.get(session))
-
- 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)
-
- args = (size, map.width, map.height, len(slots), map.rows, map.cols)
- self.set_cookie(session, args)
- self.cache_it(session, zl, map, args)
-
- writer = Writer()
- map.write(writer)
- return writer.to_string()
-
- def get_cached(self, session, zl):
- filename = self.gen_filename(session)
- return self.cache.find_recent(filename, self.max_png_age)
-
- def cache_it(self, session, zl, map, args):
- filename = self.gen_filename(session)
- writer = self.cache.create_cache_file(filename, args)
- map.write(writer)
-
- def gen_filename(self, session):
- return session.marshal()
-
- def set_cookie(self, session, args):
- cookie = "|".join((str(x) for x in args))
- session.set_cookie("slot_info", cookie)
-
class PieChartPage(Page):
def __init__(self, app, name):
super(PieChartPage, self).__init__(app, name)
- self.class_ = CuminClassParameter(app, "class")
- self.add_parameter(self.class_)
+ self.cls = CuminClassParameter(app, "class")
+ self.add_parameter(self.cls)
self.id = IntegerParameter(app, "id")
self.add_parameter(self.id)
@@ -384,7 +268,7 @@
return "no-cache"
def get_object(self, session):
- cls = self.class_.get(session).mint_class
+ cls = self.cls.get(session).mint_class
id = self.id.get(session)
return (cls.get(id),)
@@ -392,8 +276,8 @@
def __init__(self, app, name):
super(StatChartPage, self).__init__(app, name)
- self.class_ = CuminClassParameter(app, "class")
- self.add_parameter(self.class_)
+ self.cls = CuminClassParameter(app, "class")
+ self.add_parameter(self.cls)
self.id = IntegerParameter(app, "id")
self.add_parameter(self.id)
@@ -440,7 +324,7 @@
return "no-cache"
def get_object(self, session):
- cls = self.class_.get(session).mint_class
+ cls = self.cls.get(session).mint_class
id = self.id.get(session)
return (cls.get(id),)
@@ -497,7 +381,7 @@
object = self.get_object(session)[0]
colors = ((1,0,0), (0,0,1), (0,1,0))
- cls = self.class_.get(session)
+ cls = self.cls.get(session)
stats = [getattr(cls, x) for x in self.stats.get(session)]
recent = None
@@ -607,19 +491,19 @@
def __init__(self, app, name):
super(FlashFullPage, self).__init__(app, name)
- self.flash_chart = self.GenericChart(app, "chart")
- self.add_child(self.flash_chart)
-
self.updater = Widget(app, "updater")
self.updater.update_enabled = True
self.add_child(self.updater)
- self.class_ = CuminClassParameter(app, "class")
- self.add_parameter(self.class_)
+ self.cls = CuminClassParameter(app, "class")
+ self.add_parameter(self.cls)
self.id = IntegerParameter(app, "id")
self.add_parameter(self.id)
+ self.object = self.ObjectAttribute(app, "object")
+ self.add_attribute(self.object)
+
param = Parameter(app, "param")
self.add_parameter(param)
@@ -640,15 +524,24 @@
self.chart_type = Parameter(app, "type")
self.add_parameter(self.chart_type)
+ self.flash_chart = self.GenericChart(app, "chart", self.object)
+ self.add_child(self.flash_chart)
+
def render_content(self, session):
self.flash_chart.stats = self.stats.get(session)
self.flash_chart.mode = self.mode.get(session)
self.flash_chart.chart_type = self.chart_type.get(session)
return self.flash_chart.render(session)
+ class ObjectAttribute(Attribute):
+ def get(self, session):
+ cls = self.widget.cls.get(session).mint_class
+ id = self.widget.id.get(session)
+ return cls.get(id)
+
class GenericChart(StatFlashChart):
def get_args(self, session):
- cls = self.parent.class_.get(session).mint_class
+ cls = self.parent.cls.get(session).mint_class
id = self.parent.id.get(session)
return (cls.get(id),)
@@ -722,7 +615,7 @@
names = self.page.names.get(session)
values = self.page.values.get(session)
- #cls = self.page.class_.get(session)
+ #cls = self.page.cls.get(session)
#action = self.page.action.get(session)
#method = getattr(cls, action)
#values1 = method.do_invoke(object)
@@ -1201,7 +1094,7 @@
return "text/plain"
def get_stats(self, session):
- cls = self.class_.get(session)
+ cls = self.cls.get(session)
return [getattr(cls, x) for x in self.stats.get(session)]
def do_render(self, session):
@@ -1224,7 +1117,7 @@
class StatStackedPage(StatChartPage):
def do_render(self, session):
object = self.get_object(session)[0]
- cls = self.class_.get(session)
+ cls = self.cls.get(session)
stats = [getattr(cls, x) for x in self.stats.get(session)]
if len(stats):
Deleted: mgmt/trunk/cumin/python/cumin/visualizations.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/visualizations.py 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/visualizations.py 2009-08-27 19:52:28 UTC (rev 3594)
@@ -1,182 +0,0 @@
-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 *
-
-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)
-
- 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")
- object = args[0]
- try:
- if isinstance(object, Sysimage):
- scheduler = Scheduler.select("system='%s'" % object.nodeName)[0]
- else:
- scheduler = Scheduler.select("pool='%s'" % object.id)[0]
- return self.page.main.grid.pool.job.get_href(session, job, scheduler)
- except:
- pass
-
- def render_slot_clip_size(self, session, *args):
- return 400
-
- 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"),
- ("Retiring", "purple"),
- ("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)
- vis = CuminVisualization(self.app)
- itemset = vis.get_itemset_by_name(cls.cumin_name)
- slot_info = itemset.get_info(session, object.id)
- 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 ""
- return item[0] == "Job ID" and "id='job_id'" or ""
-
- def render_row_class(self, session, item):
- return item[0] == "jid" and "class='hidden_row'" or ""
-
-class CuminVisualization(object):
- def __init__(self, app):
- self.app = app
- self.itemsets = dict()
-
- from grid.pool import PoolVisualization
- from inventory.system import SystemVisualization
- PoolVisualization(self, app, "pool")
- SystemVisualization(self, app, "system")
-
- def get_itemset_by_name(self, name):
- if name in self.itemsets:
- return self.itemsets[name]
-
- def add_visualization(self, itemset, name):
- self.itemsets[name] = itemset
Deleted: mgmt/trunk/cumin/python/cumin/visualizations.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/visualizations.strings 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/visualizations.strings 2009-08-27 19:52:28 UTC (rev 3594)
@@ -1,1172 +0,0 @@
-[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.notify = function(fullpage, size) {
- slot_clip_size = size;
- this.img_loaded(document.images[slot_current_id]);
- }
- 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 = vis.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);
- }
-
- this.get_index = function (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 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;
- var branch = wooly.session.branch(src);
- branch.zl = level;
- branch.zx = slot_clip_left;
- branch.zy = slot_clip_top;
- src = branch.marshal();
-
- src = cumin.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();
- cumin.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 = vis.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
- if ((slot_map_info.size == 0) || (slot_zoom == 0))
- return 1;
- 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";
- }
- }
- $("slot_visualization").style.display = "block";
- cumin.makeFullPageable($("slot_visualization"));
- 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 = $(slot_info_id);
- if (oInfo) {
- oInfo.style.visibility = "hidden";
- }
- slot_last_index = -1;
- }
-
- function get_slot_info(rx, ry) {
- var click_info = vis.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 = $(slot_info_id);
- 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 refire_info() {
- if (slot_last_index > -1) {
- do_info_request(slot_last_index)
- }
- }
-
- function do_info_request(index) {
- var branch = wooly.session.branch(slot_info_url);
- branch.session[slot_info_index] = index;
- var newreq = branch.marshal();
- wooly.setIntervalUpdate(newreq, got_slot_info, 0, {index: index});
- }
-
- function got_slot_info(xhtml, args) {
- if (slot_last_index == -1) return;
- var oInfo = $(slot_info_id);
- 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 = $(slot_info_id);
- if (oInfo) {
- oInfo.click_index = args.index;
- oInfo.for_jid = null;
- if (for_jid) {
- clicks.doClick(for_jid.x, for_jid.y);
- return;
- }
-
- document.body.appendChild(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
- // just under the clicked slot
- var topUnder = (abs_pos.y + y) + Math.floor(slot_map_info.size * 1.5);
- var top = topUnder;
-
- // if off the bottom of the map
- if (topUnder + 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);
- }
-
- // if off the top of the page
- if (top < 0) {
- // revert to under the item
- top = topUnder;
- }
-
- 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();
- clicks.click_when = d.getTime();
- var rpos = get_relative_event_pos(e);
- if (rpos) {
- clicks.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 = vis.get_index(x, y);
- var oInfo = $(slot_info_id);
- 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;
- }
- }
- }
-
- 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();
- clicks.doubleclick_when = now.getTime();
- if (clicks.click_handle != null) {
- clearTimeout(clicks.click_handle); // Clear pending Click
- clicks.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};
- }
-}
-
-[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; */
- margin: 3em auto;
- padding: 1em;
- z-index:200;
- text-align: center;
- background-color: white;
- overflow: hidden;
- opacity: 0.5;
- -moz-opacity: 0.5;
- display: none;
- border: 1px solid #000;
-}
-
-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;
- display: none;
- float: left;
-}
-
-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" class="fullpageable">
- <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>
-<div style="clear: left"><!-- --></div>
-{slot_info}
-<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 original_clip_size = slot_clip_size;
- $('slot_visualization').onfullpage = function (width) { vis.notify(true, width); };
- $('slot_visualization').onrestore = function () { vis.notify(false, original_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>
-
-[SlotInfo.css]
-div.slot_info {
- position: absolute;
- top: 0;
- left: 0.5em;
- visibility: hidden;
- z-index: 301;
-}
-
-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: 0.1em;
-}
-
-div.slot_legend h3 {
- margin-top: 0;
-}
-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;
- margin-bottom: 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>
Modified: mgmt/trunk/cumin/python/cumin/widgets.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/widgets.py 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/widgets.py 2009-08-27 19:52:28 UTC (rev 3594)
@@ -1,9 +1,9 @@
from datetime import datetime, timedelta
-from sqlobject import sqlhub
from wooly import *
from wooly.pages import *
from wooly.widgets import *
from wooly.forms import *
+from wooly.sql import *
from wooly.tables import *
from mint.schema import *
@@ -34,15 +34,11 @@
self.tasks = TaskInvocationSet(app, "tasks")
self.add_child(self.tasks)
- self.actions = ActionInvocationSet(app, "actions")
- self.add_child(self.actions)
-
self.heartbeat = CuminHeartBeat(app, "heartbeat")
self.add_child(self.heartbeat)
def do_process(self, session, *args):
self.tasks.process(session)
- self.actions.process(session)
self.heartbeat.process(session)
super(CuminMainView, self).do_process(session, *args)
@@ -59,9 +55,6 @@
if hasattr(session, "user_session"):
return session.user_session.subject.name
- def render_action_display(self, session):
- return self.actions.get_item_count(session) > 0 and "block" or "none"
-
def render_logout_href(self, session):
page = self.app.login_page
@@ -132,27 +125,26 @@
return cls.get_object_title(session, obj)
class CuminView(Widget):
- def __init__(self, app, name):
+ def __init__(self, app, name, object):
super(CuminView, self).__init__(app, name)
- self.__frame_tmpl = Template(self, "frame_html")
+ self.object = object
- summary = CuminSummary(app, "summary")
+ summary = CuminSummary(app, "summary", self.object)
self.add_child(summary)
- def get_args(self, session):
- return self.frame.get_args(session)
+ self.__frame_tmpl = Template(self, "frame_html")
- def render_script(self, session, *args):
+ def render_script(self, session):
return None
- def render_icon_resource(self, session, *args):
+ def render_icon_resource(self, session):
return "action-36.png"
- def render_title(self, session, *args):
- return self.frame.render_title(session, *args)
+ def render_title(self, session):
+ return self.frame.render_title(session)
- def render_frames(self, session, *args):
+ def render_frames(self, session):
writer = Writer()
for frame in self.page.get_frames(session)[:-1]:
@@ -161,12 +153,10 @@
return writer.to_string()
def render_frame_href(self, session, frame):
- args = frame.get_args(session)
- return frame.render_href(session, *args)
+ return frame.render_href(session)
def render_frame_title(self, session, frame):
- args = frame.get_args(session)
- return frame.render_title(session, *args)
+ return frame.render_title(session)
class BackgroundInclude(Widget):
def __init__(self, app, name):
@@ -194,10 +184,10 @@
assert isinstance(self.object, Parameter)
def process_submit(self, session):
- object = self.object.get(session)
+ obj = self.object.get(session)
- self.task.invoke(session, object)
- self.task.exit_with_redirect(session, object)
+ self.task.invoke(session, obj)
+ self.task.exit_with_redirect(session, obj)
def render_submit_content(self, session):
return self.task.get_title(session)
@@ -206,8 +196,8 @@
return "Confirm"
def render_content(self, session):
- object = self.object.get(session)
- return "%s?" % self.task.get_description(session, object)
+ obj = self.object.get(session)
+ return "%s?" % self.task.get_description(session, obj)
class FormHelp(Widget):
def __init__(self, app, name):
@@ -366,24 +356,17 @@
return "error" in item and "numeric_error" or "edit_number"
class CuminProperties(PropertySet):
- def get_args(self, session):
- return self.frame.get_args(session)
+ def __init__(self, app, name, object):
+ super(CuminProperties, self).__init__(app, name)
- def do_get_items(self, session, object):
- cls = self.app.model.get_class_by_object(object)
- return [(x.get_title(session), x.value(session, object), x.escape)
- for x in cls.properties]
+ self.object = object
-class CuminActions(ActionSet):
- def get_args(self, session):
- return self.frame.get_args(session)
+ def do_get_items(self, session):
+ obj = self.object.get(session)
+ cls = self.app.model.get_class_by_object(obj)
- def do_get_items(self, session, object):
- cls = self.app.model.get_class_by_object(object)
- return [(x.get_href(session, object),
- x.get_title(session),
- x.get_enabled(session, object))
- for x in cls.actions if x.navigable and not x.aggregate]
+ return [(x.get_title(session), x.value(session, obj), x.escape)
+ for x in cls.properties]
class CuminTasks(ActionSet):
def __init__(self, app, name, object):
@@ -392,23 +375,17 @@
self.object = object
def do_get_items(self, session):
- if self.object:
- object = self.object.get(session)
- cls = self.app.model.get_class_by_object(object)
+ obj = self.object.get(session)
+ cls = self.app.model.get_class_by_object(obj)
- return [(x.get_href(session, object),
- x.get_title(session),
- True)
- for x in cls.tasks if x.navigable and not x.aggregate]
+ return [(x.get_href(session, obj), x.get_title(session), True)
+ for x in cls.tasks if x.navigable and not x.aggregate]
class CuminDetails(Widget):
- # XXX make the object arg mandatory
-
- def __init__(self, app, name, object=None):
+ def __init__(self, app, name, object):
super(CuminDetails, self).__init__(app, name)
- self.add_child(CuminProperties(app, "properties"))
- self.add_child(CuminActions(app, "actions"))
+ self.add_child(CuminProperties(app, "properties", object))
self.add_child(CuminTasks(app, "tasks", object))
def render_title(self, session):
@@ -422,52 +399,51 @@
return "resource?name=action-36.png"
class CuminSummary(Widget):
- def __init__(self, app, name):
+ def __init__(self, app, name, object):
super(CuminSummary, self).__init__(app, name)
- props = self.SummaryProperties(app, "properties")
+ self.object = object
+
+ props = self.SummaryProperties(app, "properties", self.object)
self.add_child(props)
- actions = self.SummaryActions(app, "actions")
- self.add_child(actions)
-
- tasks = self.SummaryTasks(app, "tasks")
+ tasks = self.SummaryTasks(app, "tasks", self.object)
self.add_child(tasks)
- def get_args(self, session):
- return self.frame.get_args(session)
+ def render_title(self, session):
+ obj = self.object.get(session)
+ cls = self.app.model.get_class_by_object(obj)
- def render_title(self, session, object):
- cls = self.app.model.get_class_by_object(object)
if cls:
- return cls.get_object_title(session, object)
+ return cls.get_object_title(session, obj)
- def render_icon_href(self, session, object):
- cls = self.app.model.get_class_by_object(object)
+ def render_icon_href(self, session):
+ obj = self.object.get(session)
+ cls = self.app.model.get_class_by_object(obj)
+
if cls:
return cls.get_icon_href(session)
class SummaryProperties(CuminProperties):
- def do_get_items(self, session, object):
- cls = self.app.model.get_class_by_object(object)
- if cls:
- return [(x.get_title(session), x.value(session, object), x.escape)
- for x in cls.properties if x.summary]
+ def do_get_items(self, session):
+ obj = self.object.get(session)
+ cls = self.app.model.get_class_by_object(obj)
- class SummaryActions(CuminActions):
- def do_get_items(self, session, object):
- cls = self.app.model.get_class_by_object(object)
if cls:
- return [(x.get_href(session, object), x.get_title(session), x.get_enabled(session, object))
- for x in cls.actions if x.summary and x.navigable]
+ return [(x.get_title(session),
+ x.value(session, obj),
+ x.escape)
+ for x in cls.properties if x.summary]
- class SummaryTasks(CuminActions):
- def do_get_items(self, session, object):
- cls = self.app.model.get_class_by_object(object)
+ class SummaryTasks(CuminTasks):
+ def do_get_items(self, session):
+ obj = self.object.get(session)
+ cls = self.app.model.get_class_by_object(obj)
+
if cls:
- return [(x.get_href(session, object),
+ return [(x.get_href(session, obj),
x.get_title(session),
- x.is_enabled(session, object))
+ x.is_enabled(session, obj))
for x in cls.tasks
if not x.aggregate and x.form and x.navigable]
@@ -739,7 +715,7 @@
self.add_attribute(self.count)
def get_connection(self, session):
- return sqlhub.getConnection().getConnection()
+ return self.app.model.get_sql_connection()
class CountColumn(TopTableCountColumn):
def render_content(self, session, data):
@@ -761,6 +737,10 @@
self.paginator.set_count(session, self.get_item_count(session, *args))
+class CuminSqlDataSet(SqlDataSet):
+ def get_connection(self, session):
+ return self.app.model.get_sql_connection()
+
class CuminTable(TruncatableTable):
def __init__(self, app, name):
super(CuminTable, self).__init__(app, name)
@@ -771,7 +751,7 @@
self.update_enabled = True
def get_connection(self, session):
- return sqlhub.getConnection().getConnection()
+ return self.app.model.get_sql_connection()
def do_process(self, session, *args):
super(CuminTable, self).do_process(session, *args)
Modified: mgmt/trunk/cumin/python/cumin/widgets.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/widgets.strings 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/cumin/python/cumin/widgets.strings 2009-08-27 19:52:28 UTC (rev 3594)
@@ -248,8 +248,6 @@
{properties}
</td>
<td>
- <h2>Actions</h2>
- {actions}
<h2>Tasks</h2>
{tasks}
</td>
@@ -297,7 +295,7 @@
padding: 0;
}
-div.CuminSummary div.actions {
+div.CuminSummary div.tasks {
font-size: 0.9em;
width: 20em;
float: right;
@@ -316,8 +314,7 @@
<hr/>
- <div class="actions">
- {actions}
+ <div class="tasks">
{tasks}
</div>
Modified: mgmt/trunk/wooly/python/wooly/__init__.py
===================================================================
--- mgmt/trunk/wooly/python/wooly/__init__.py 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/wooly/python/wooly/__init__.py 2009-08-27 19:52:28 UTC (rev 3594)
@@ -11,6 +11,35 @@
strings = StringCatalog(__file__)
+class SessionAttribute(object):
+ def __init__(self, object, name):
+ self.object = object
+ self.name = name
+ self.default = None
+
+ self.key = (self.object, self.name)
+
+ def get_default(self, session):
+ return copy(self.default)
+
+ def get(self, session):
+ value = session.get(self.key)
+
+ if value is None:
+ value = self.get_default(session)
+
+ if value is not None:
+ self.set(session, value)
+
+ return value
+
+ def add(self, session, value):
+ self.set(session, value)
+
+ def set(self, session, value):
+ session.set(self.key, value)
+
+# XXX make this more definitely WidgetAttribute
class Attribute(object):
def __init__(self, app, name):
self.app = app
@@ -38,12 +67,11 @@
def get(self, session):
value = session.get(self.path)
- # Use strict test because empty collections are False
if value is None:
- default = self.get_default(session)
+ value = self.get_default(session)
- if default is not None:
- value = self.set(session, default)
+ if value is not None:
+ self.set(session, value)
return value
@@ -51,6 +79,7 @@
self.set(session, value)
def set(self, session, value):
+ # XXX don't return the value
return session.set(self.path, value)
def get_default(self, session):
@@ -790,7 +819,7 @@
class Writer(StringIOWriter):
pass
-class ObjectBoundTemplate(object):
+class ObjectTemplate(object):
def __init__(self, obj, text):
self.__object = obj
self.__text = text
@@ -891,7 +920,7 @@
name = self.__object.__class__.__name__ + "." + self.key
return "%s('%s')" % (self.__class__.__name__, name)
-class Template(ObjectBoundTemplate):
+class WidgetTemplate(ObjectTemplate):
def __init__(self, widget, key):
text = widget.get_string(key)
@@ -899,13 +928,17 @@
raise Exception("Template '%s.%s' not found" \
% (widget.__class__.__name__, key))
- super(Template, self).__init__(widget, text)
+ super(WidgetTemplate, self).__init__(widget, text)
self.widget = widget
def find_child(self, name):
return self.widget.children_by_name.get(name)
+# XXX eliminate this leftover alias
+class Template(WidgetTemplate):
+ pass
+
class WidgetCall(object):
def __init__(self, stack, widget, session, object):
self.stack = stack
Added: mgmt/trunk/wooly/python/wooly/sql.py
===================================================================
--- mgmt/trunk/wooly/python/wooly/sql.py (rev 0)
+++ mgmt/trunk/wooly/python/wooly/sql.py 2009-08-27 19:52:28 UTC (rev 3594)
@@ -0,0 +1,97 @@
+import logging
+
+from wooly import *
+
+strings = StringCatalog(__file__)
+log = logging.getLogger("wooly.sql")
+
+class SqlDataSet(object):
+ def __init__(self, app):
+ super(SqlDataSet, self).__init__()
+
+ self.app = app
+
+ sql_string = self.get_string("sql")
+ count_sql_string = self.get_string("count_sql")
+
+ self.sql_tmpl = ObjectTemplate(self, sql_string)
+ self.count_sql_tmpl = ObjectTemplate(self, count_sql_string)
+
+ self.where_exprs = SessionAttribute(self, "where")
+
+ self.limit = SessionAttribute(self, "limit")
+ self.limit.default = "all"
+
+ self.offset = SessionAttribute(self, "offset")
+ self.offset.default = 0
+
+ def add_where_expr(self, session, expr, *args):
+ exprs = self.where_exprs.get(session)
+ exprs.append(expr % args)
+
+ # XXX instead of this, make the lookup logic on Widget generic and
+ # use it here as well
+ def get_string(self, key):
+ cls = self.__class__
+ module = sys.modules[cls.__module__]
+ strs = module.__dict__.get("strings")
+
+ if strs:
+ return strs.get(cls.__name__ + "." + key)
+
+ def get_connection(self, session):
+ pass
+
+ def get_items(self, session):
+ return self.execute(session).fetchall()
+
+ def do_execute(self, session, sql):
+ conn = self.get_connection(session)
+
+ if not conn:
+ raise Exception("Database error")
+
+ cursor = conn.cursor()
+
+ log.debug("Query: \n%s", sql)
+
+ cursor.execute(sql)
+
+ return cursor
+
+ def execute(self, session):
+ sql = self.render_sql(session)
+
+ return self.do_execute(session, sql)
+
+ def count(self, session):
+ sql = self.render_count_sql(session)
+ values = self.values.get(session)
+
+ cursor = self.do_execute(session, sql, values)
+ data = cursor.fetchone()
+
+ return data[0]
+
+ def render_sql(self, session):
+ writer = Writer()
+ self.sql_tmpl.render(writer, session)
+ return writer.to_string()
+
+ def render_count_sql(self, session):
+ writer = Writer()
+ self.count_sql_tmpl.render(writer, session)
+ return writer.to_string()
+
+ def render_sql_where(self, session):
+ exprs = self.where_exprs.get(session)
+ return "where %s" % " and ".join(exprs)
+
+ def render_sql_order_by(self, session):
+ pass
+
+ def render_sql_limit(self, session):
+ limit = self.limit.get(session)
+ offset = self.offset.get(session)
+
+ return "limit %s offset %i" % (str(limit), offset)
Modified: mgmt/trunk/wooly/python/wooly/tables.py
===================================================================
--- mgmt/trunk/wooly/python/wooly/tables.py 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/wooly/python/wooly/tables.py 2009-08-27 19:52:28 UTC (rev 3594)
@@ -225,16 +225,6 @@
self.__find_sql_tmpl.render(writer, session, *args)
return writer.to_string()
- def build_sql(self, elems):
- writer = Writer()
-
- for elem in elems:
- if elem:
- writer.write(elem)
- writer.write("\n")
-
- return writer.to_string()
-
def get_sql_where_constraints(self, session, *args):
return list()
@@ -250,31 +240,35 @@
def get_item_count(self, session, *args):
conn = self.get_connection(session)
- if conn:
- cursor = conn.cursor()
- sql = self.render_count_sql(session, *args)
- sql_values = self.get_sql_values(session, *args)
+ if not conn:
+ raise Exception("Database error")
+
+ cursor = conn.cursor()
+ sql = self.render_count_sql(session, *args)
+ sql_values = self.get_sql_values(session, *args)
- cursor.execute(sql, sql_values)
- data = cursor.fetchone()
+ cursor.execute(sql, sql_values)
+ data = cursor.fetchone()
- return data[0]
+ return data[0]
def do_get_items(self, session, *args):
conn = self.get_connection(session)
- if conn:
- cursor = conn.cursor()
- sql = self.render_sql(session, *args)
- sql_values = self.get_sql_values(session, *args)
+ if not conn:
+ raise Exception("Database error")
- #print "SQL TEXT", sql
- #print "SQL VALS", sql_values
+ cursor = conn.cursor()
+ sql = self.render_sql(session, *args)
+ sql_values = self.get_sql_values(session, *args)
- cursor.execute(sql, sql_values)
+ #print "SQL TEXT", sql
+ #print "SQL VALS", sql_values
- return cursor
+ cursor.execute(sql, sql_values)
+ return cursor
+
def render_items(self, session, *args):
cursor = self.get_items(session, *args)
cols = [spec[0] for spec in cursor.description]
Modified: mgmt/trunk/wooly/python/wooly/widgets.py
===================================================================
--- mgmt/trunk/wooly/python/wooly/widgets.py 2009-08-27 19:19:13 UTC (rev 3593)
+++ mgmt/trunk/wooly/python/wooly/widgets.py 2009-08-27 19:52:28 UTC (rev 3594)
@@ -58,7 +58,7 @@
self.__tabs.append(tab)
self.add_mode(tab)
- def render_tabs(self, session, *args):
+ def render_tabs(self, session):
writer = Writer()
for tab in self.__tabs:
@@ -76,8 +76,7 @@
return mode is tab and "class=\"selected\"" or ""
def render_tab_content(self, session, tab):
- args = tab.get_args(session)
- return tab.render_title(session, *args)
+ return tab.render_title(session)
class RadioModeSet(TabbedModeSet):
""" exists just to provide different class/styles """
@@ -183,6 +182,7 @@
if items is None:
items = self.do_get_items(session, *args)
+
if items is None:
items = ()
@@ -257,7 +257,7 @@
super(TemplateRenderer, self).__init__(widget)
text = self.widget.get_string(template_key)
- self.__tmpl = ObjectBoundTemplate(self, text)
+ self.__tmpl = ObjectTemplate(self, text)
def render(self, writer, session, item):
self.__tmpl.render(writer, session, item)
15 years, 3 months
rhmessaging commits: r3593 - mgmt/trunk/basil/python/basil.
by rhmessaging-commits@lists.jboss.org
Author: justi9
Date: 2009-08-27 15:19:13 -0400 (Thu, 27 Aug 2009)
New Revision: 3593
Modified:
mgmt/trunk/basil/python/basil/model.py
mgmt/trunk/basil/python/basil/page.py
mgmt/trunk/basil/python/basil/server.py
Log:
* Store a fixed number of stats
* Take advantage of defaultdict and deque
* Add logic to find readable object names, and shorten them if
they're too long
Modified: mgmt/trunk/basil/python/basil/model.py
===================================================================
--- mgmt/trunk/basil/python/basil/model.py 2009-08-26 19:29:55 UTC (rev 3592)
+++ mgmt/trunk/basil/python/basil/model.py 2009-08-27 19:19:13 UTC (rev 3593)
@@ -1,3 +1,4 @@
+from collections import defaultdict, deque
from qmf.console import *
from threading import Lock
@@ -13,10 +14,10 @@
self.lock = Lock()
self.packages = set()
- self.classes_by_package = dict()
- self.objects_by_class = dict()
+ self.classes_by_package = defaultdict(dict)
+ self.objects_by_class = defaultdict(dict)
self.objects_by_id = dict()
- self.stats_by_id = dict()
+ self.stats_by_id = defaultdict(StatsRecord)
def add_broker_url(self, url):
self.broker_urls.add(url)
@@ -60,29 +61,42 @@
try:
pkgid = classKey.getPackageName()
- classes = self.model.classes_by_package.setdefault(pkgid, dict())
+ classes = self.model.classes_by_package[pkgid]
classes[classKey.getHashString()] = classKey
finally:
self.model.lock.release()
- def objectProps(self, broker, object):
+ def objectProps(self, broker, obj):
self.model.lock.acquire()
try:
- clsid = object.getClassKey().getHashString()
- objects = self.model.objects_by_class.setdefault(clsid, dict())
- objects[str(object.getObjectId())] = object
+ clsid = obj.getClassKey().getHashString()
+ objs = self.model.objects_by_class[clsid]
+ objs[str(obj.getObjectId())] = obj
- self.model.objects_by_id[str(object.getObjectId())] = object
+ self.model.objects_by_id[str(obj.getObjectId())] = obj
finally:
self.model.lock.release()
- def objectStats(self, broker, object):
+ def objectStats(self, broker, obj):
self.model.lock.acquire()
try:
- objid = str(object.getObjectId())
- stats = self.model.stats_by_id.setdefault(objid, list())
- stats.append(object)
+ objid = str(obj.getObjectId())
+ stats = self.model.stats_by_id[objid]
+
+ for stat in obj.getStatistics():
+ name = stat[0].name
+ value = stat[1]
+
+ values = stats[name]
+ values.append(value)
+
+ if len(values) > 10:
+ values.popleft()
finally:
self.model.lock.release()
+
+class StatsRecord(defaultdict):
+ def __init__(self):
+ super(StatsRecord, self).__init__(deque)
Modified: mgmt/trunk/basil/python/basil/page.py
===================================================================
--- mgmt/trunk/basil/python/basil/page.py 2009-08-26 19:29:55 UTC (rev 3592)
+++ mgmt/trunk/basil/python/basil/page.py 2009-08-27 19:19:13 UTC (rev 3593)
@@ -131,18 +131,12 @@
return "Classes"
class NameColumn(SelectableNameColumn):
- def get_id(self, object):
- return str(object.getObjectId())
+ def get_id(self, obj):
+ return str(obj.getObjectId())
- def get_name(self, object):
- return object.getIndex()
+ def get_name(self, obj):
+ return get_object_name(obj)
-# if hasattr(object, "name"):
-# return getattr(object, "name")
-# else:
-# return self.get_id(object)
- #return getattr(object, "name", self.get_id(object)) # XXX use this
-
class ObjectView(Widget):
def __init__(self, app, name, objid):
super(ObjectView, self).__init__(app, name)
@@ -161,7 +155,8 @@
id = self.objid.get(session)
try:
- return self.app.model.objects_by_id[id].getIndex()
+ obj = self.app.model.objects_by_id[id]
+ return get_object_name(obj)
except KeyError:
pass
@@ -170,6 +165,7 @@
try:
utime = self.app.model.objects_by_id[id].getTimestamps()[index]
+
if utime != 0:
utime = utime / float(1000000000)
return datetime.fromtimestamp(utime)
@@ -185,39 +181,57 @@
def render_delete_time(self, session):
return self.render_timestamp(session, 2)
-class BaseObjectProperties(PropertySet):
+class ObjectProperties(PropertySet):
def __init__(self, app, name, objid):
- super(BaseObjectProperties, self).__init__(app, name)
+ super(ObjectProperties, self).__init__(app, name)
self.objid = objid
def do_get_items(self, session):
id = self.objid.get(session)
- obj = self.app.model.objects_by_id.get(id)
- if obj:
- return self.get_properties(obj)
+ try:
+ obj = self.app.model.objects_by_id[id]
+ return obj.getProperties()
+ except KeyError:
+ pass
- def get_properties(self, object):
- return object.getProperties()
-
def get_item_name(self, item):
- return str(item[0])
+ return shorten(item[0])
def get_item_value(self, item):
- return str(item[1])
+ return shorten(item[1])
-class ObjectProperties(BaseObjectProperties):
- def get_properties(self, object):
- return object.getProperties()
+class ObjectStatistics(PropertySet):
+ def __init__(self, app, name, objid):
+ super(ObjectStatistics, self).__init__(app, name)
-class ObjectStatistics(BaseObjectProperties):
+ self.objid = objid
+
def do_get_items(self, session):
id = self.objid.get(session)
stats = self.app.model.stats_by_id.get(id)
if stats:
- return self.get_properties(stats[-1])
+ return stats.items()
- def get_properties(self, object):
- return object.getStatistics()
+ def get_item_name(self, item):
+ return shorten(item[0])
+
+ def get_item_value(self, item):
+ return ", ".join([str(x) for x in reversed(item[1])])
+
+def get_object_name(obj):
+ for prop, value in obj.getProperties():
+ if prop.name in ("name", "Name"):
+ return value
+
+ return shorten(obj.getIndex())
+
+def shorten(value):
+ value = str(value)
+
+ if len(value) > 32:
+ value = value[0:32] + "..."
+
+ return value
Modified: mgmt/trunk/basil/python/basil/server.py
===================================================================
--- mgmt/trunk/basil/python/basil/server.py 2009-08-26 19:29:55 UTC (rev 3592)
+++ mgmt/trunk/basil/python/basil/server.py 2009-08-27 19:19:13 UTC (rev 3593)
@@ -14,14 +14,14 @@
super(BasilApplication, self).__init__()
self.model = BasilModel()
- self.model.add_broker_url("amqp://mrg2.lab.bos.redhat.com")
+ self.model.add_broker_url("amqp://mrg31.lab.bos.redhat.com")
self.main_page = BasilPage(self, "index.html")
self.add_page(self.main_page)
self.set_default_page(self.main_page)
- self.add_resource_dir("/home/jross/checkouts/mgmt/trunk/cumin-test-0/resources-wooly") # XXX
+ self.add_resource_dir("/home/boston/jross/local/mgmt/cumin/instance/resources-wooly") # XXX
self.enable_debug()
15 years, 3 months
rhmessaging commits: r3592 - mgmt/trunk/cumin/python/cumin.
by rhmessaging-commits@lists.jboss.org
Author: eallen
Date: 2009-08-26 15:29:55 -0400 (Wed, 26 Aug 2009)
New Revision: 3592
Modified:
mgmt/trunk/cumin/python/cumin/model.py
Log:
Default GROUP_NAMES to None so we don't get a phantom empty row when there are no groups
Modified: mgmt/trunk/cumin/python/cumin/model.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/model.py 2009-08-26 13:13:33 UTC (rev 3591)
+++ mgmt/trunk/cumin/python/cumin/model.py 2009-08-26 19:29:55 UTC (rev 3592)
@@ -2418,7 +2418,7 @@
class GetRawConfig(CuminAction):
def do_invoke(self, negotiator, config_name, timeout=5):
- default = {'Value': ""}
+ default = {'Value': None}
qmf = QMFCaller(default)
negotiator.GetRawConfig(self.mint.model, qmf.get_completion(), config_name, None)
wait(qmf.done, timeout=timeout)
15 years, 4 months
rhmessaging commits: r3591 - mgmt/trunk/cumin/python/cumin.
by rhmessaging-commits@lists.jboss.org
Author: eallen
Date: 2009-08-26 09:13:33 -0400 (Wed, 26 Aug 2009)
New Revision: 3591
Modified:
mgmt/trunk/cumin/python/cumin/model.py
Log:
Don't wait so long for failed GetAd and GetJobs calls
Modified: mgmt/trunk/cumin/python/cumin/model.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/model.py 2009-08-25 23:01:05 UTC (rev 3590)
+++ mgmt/trunk/cumin/python/cumin/model.py 2009-08-26 13:13:33 UTC (rev 3591)
@@ -2233,7 +2233,7 @@
default = {'JobAd': {"":{"VALUE":"", "TYPE":0}}}
qmf = QMFCaller(default)
scheduler.GetAd(self.mint.model, qmf.get_completion(), job, None)
- wait(qmf.done, timeout=10)
+ wait(qmf.done, timeout=5)
return qmf.data['JobAd']
@@ -2243,7 +2243,7 @@
default = {'Jobs': {}}
qmf = QMFCaller(default)
scheduler.GetJobs(self.mint.model, qmf.get_completion(), submission, None)
- wait(qmf.done, timeout=10)
+ wait(qmf.done, timeout=5)
return qmf.data['Jobs']
15 years, 4 months
rhmessaging commits: r3590 - mgmt/trunk/cumin/python/cumin.
by rhmessaging-commits@lists.jboss.org
Author: eallen
Date: 2009-08-25 19:01:05 -0400 (Tue, 25 Aug 2009)
New Revision: 3590
Modified:
mgmt/trunk/cumin/python/cumin/model.py
Log:
Split out the job id from the job name returned from the qmf GetJobs call
Modified: mgmt/trunk/cumin/python/cumin/model.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/model.py 2009-08-25 22:43:32 UTC (rev 3589)
+++ mgmt/trunk/cumin/python/cumin/model.py 2009-08-25 23:01:05 UTC (rev 3590)
@@ -1902,7 +1902,12 @@
class Job(object):
def __init__(self, id):
- self.id = id
+ real_id = id
+ sched, sep, jid = id.partition('#')
+ if jid:
+ real_id, sep, proc = jid.partition('#')
+
+ self.id = real_id
self.name = id
def get(cls, id):
15 years, 4 months
rhmessaging commits: r3589 - mgmt/trunk/cumin/python/cumin/grid.
by rhmessaging-commits@lists.jboss.org
Author: eallen
Date: 2009-08-25 18:43:32 -0400 (Tue, 25 Aug 2009)
New Revision: 3589
Modified:
mgmt/trunk/cumin/python/cumin/grid/job.py
Log:
escape the job commands column for display
Modified: mgmt/trunk/cumin/python/cumin/grid/job.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/job.py 2009-08-25 22:28:04 UTC (rev 3588)
+++ mgmt/trunk/cumin/python/cumin/grid/job.py 2009-08-25 22:43:32 UTC (rev 3589)
@@ -113,7 +113,7 @@
return "Command"
def render_content(self, session, data):
- return fmt_shorten(data[self.name], 0, 16)
+ return fmt_shorten(escape_entity(data[self.name]), 0, 16)
class SubmissionJob(object):
def __init__(self, app, name, job, submission):
15 years, 4 months
rhmessaging commits: r3588 - in mgmt/trunk/cumin/python/cumin: grid and 1 other directories.
by rhmessaging-commits@lists.jboss.org
Author: eallen
Date: 2009-08-25 18:28:04 -0400 (Tue, 25 Aug 2009)
New Revision: 3588
Modified:
mgmt/trunk/cumin/python/cumin/grid/job.py
mgmt/trunk/cumin/python/cumin/grid/job.strings
mgmt/trunk/cumin/python/cumin/grid/main.py
mgmt/trunk/cumin/python/cumin/grid/model.py
mgmt/trunk/cumin/python/cumin/grid/slot.py
mgmt/trunk/cumin/python/cumin/grid/submission.py
mgmt/trunk/cumin/python/cumin/inventory/system.py
mgmt/trunk/cumin/python/cumin/model.py
mgmt/trunk/cumin/python/cumin/parameters.py
mgmt/trunk/cumin/python/cumin/util.py
mgmt/trunk/cumin/python/cumin/visualizations.py
mgmt/trunk/cumin/python/cumin/visualizations.strings
mgmt/trunk/cumin/python/cumin/widgets.py
mgmt/trunk/cumin/python/cumin/widgets.strings
Log:
Change JobSet from sql based to qmf based.
Change all Job qmf method calls to use scheduler instead.
Modified: mgmt/trunk/cumin/python/cumin/grid/job.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/job.py 2009-08-25 15:20:11 UTC (rev 3587)
+++ mgmt/trunk/cumin/python/cumin/grid/job.py 2009-08-25 22:28:04 UTC (rev 3588)
@@ -16,129 +16,78 @@
strings = StringCatalog(__file__)
log = logging.getLogger("cumin.job")
-class JobSet(CuminSelectionTable):
- def __init__(self, app, name, pool):
+class JobSet(CuminQMFSelectionTable):
+ def __init__(self, app, name, submission):
item = JobParameter(app, "item")
super(JobSet, self).__init__(app, name, item)
- self.pool = pool
+ self.submission = submission
- col = self.CustomIdColumn(app, "custom_id")
+ self.update_enabled = False
+ self.defer_enabled = True
+
+ col = self.CustomIdColumn(app, "name")
self.add_column(col)
self.set_default_column(col)
- col = self.GlobalJobIdColumn(app, "global_job_id")
- col.visible = False
+ col = self.CommandColumn(app, "Cmd")
self.add_column(col)
- col = self.CommandColumn(app, "cmd")
+ col = self.StatusColumn(app, "JobStatus")
self.add_column(col)
- col = self.AccountingGroupColumn(app, "agroup")
- col.visible = False
- self.add_column(col)
-
- col = self.SchedulerColumn(app, "scheduler")
- col.visible = False
- self.add_column(col)
-
- col = self.SubmitterColumn(app, "submitter")
- col.visible = False
- self.add_column(col)
-
- col = self.ClusterIdColumn(app, "cluster_id")
+ col = self.ArgsColumn(app, "Args")
col.alignment = "right"
- col.visible = False
self.add_column(col)
- col = self.ConcurrencyLimitsColumn(app, "concurrency_limits")
- #col.visible = False
- self.add_column(col)
-
- col = self.CustomGroupColumn(app, "custom_group")
- col.visible = False
- self.add_column(col)
-
- col = self.CustomPriorityColumn(app, "custom_priority")
- col.visible = False
- self.add_column(col)
-
- col = self.StatusColumn(app, "job_status")
- self.add_column(col)
-
- col = self.TitleColumn(app, "title")
- col.visible = False
- self.add_column(col)
-
- col = self.ArgsColumn(app, "args")
- col.alignment = "right"
- col.visible = False
- self.add_column(col)
-
self.phase = JobStatusSwitch(app, "phase")
- self.add_child(self.phase)
+ self.filters.add_child(self.phase)
+ multi_param = self.SubmissionJob(app, "subjob", self.selection, submission)
+
task = main.module.job_set_hold
- button = TaskButton(app, "hold", task, self.selection)
+ button = TaskButton(app, "hold", task, multi_param)
self.buttons.add_child(button)
task = main.module.job_set_release
- button = TaskButton(app, "release", task, self.selection)
+ button = TaskButton(app, "release", task, multi_param)
self.buttons.add_child(button)
task = main.module.job_set_remove
- button = TaskButton(app, "remove", task, self.selection)
+ button = TaskButton(app, "remove", task, multi_param)
self.buttons.add_child(button)
- def get_phase_sql(self, session, phase=None):
- return self.phase.get_sql_constraint(session, phase)
+ def do_get_items(self, session, *args):
+ submission = self.submission.get(session)
+ scheduler = submission.scheduler
- def get_phase_title(self, session):
+ action = self.app.model.scheduler.GetJobs
+ jobs = action.qmfcall(scheduler, submission.Name)
+ return jobs
+
+ def filter_item(self, session, item):
state = self.phase.get(session)
- return self.phase.get_title(state)
+ if state == "All":
+ return True
- def render_sql_where(self, session, *args):
- phase = len(args) > 0 and args[0] or None
- elems = list()
- elems.append(self.get_phase_sql(session, phase))
- elems.append("s.pool = %(pool)s")
- return "where %s" % " and ".join(elems)
+ item_state = item["JobStatus"]["VALUE"]
+ item_state = JobStatusInfo.get_status_string(int(item_state))
- def render_stats_join(self, session, *args):
- phase = self.phase.get(session)
- return (phase == 'c') and "left outer join job_stats as c on c.id = j.stats_curr_id" or ""
+ return state == item_state
- def get_sql_values(self, session, *args):
- pool = self.pool.get(session)
- return {"pool": pool.id}
+ def render_deferred_content(self, session, *args):
+ return "Loading..."
- class ArgsColumn(SqlTableColumn):
+ def get_phase_title(self, session):
+ state = self.phase.get(session)
+ return self.phase.get_title(state)
+
+ class ArgsColumn(QmfTableColumn):
def render_title(self, session, data):
return "Arguments"
- class ClusterIdColumn(SqlTableColumn):
+ class CustomIdColumn(QmfTableColumn):
def render_title(self, session, data):
- return "Cluster Id"
-
- class ConcurrencyLimitsColumn(SqlTableColumn):
- def render_title(self, session, data):
- return "Limits"
-
- class CustomGroupColumn(SqlTableColumn):
- def render_title(self, session, data):
- return "Job Group"
-
- def render_content(self, session, data):
- name = data[self.name]
-
- if name:
- group = Identifiable(name)
- href = self.page.main.grid.pool.job_group.get_href \
- (session, group)
- return fmt_link(href, fmt_shorten(name, 12, 3))
-
- class CustomIdColumn(SqlTableColumn):
- def render_title(self, session, data):
return "ID"
def render_content(self, session, data):
@@ -146,75 +95,34 @@
if id:
job = Identifiable(data["id"])
- href = self.page.main.grid.pool.job.get_href(session, job)
- return fmt_link(href, fmt_shorten(id, 12, 3))
+ scheduler = self.parent.submission.get(session).scheduler
+ href = self.page.main.grid.pool.job.get_href(session, job, scheduler)
+ job_id, hash, num = id.rpartition('#')
+ return fmt_link(href, job_id, link_title=id)
- class CustomPriorityColumn(SqlTableColumn):
+ class StatusColumn(QmfTableColumn):
def render_title(self, session, data):
- return "Custom Priority"
-
- class GlobalJobIdColumn(SqlTableColumn):
- def render_title(self, session, data):
- return "Global Job Id"
-
- def render_content(self, session, data):
- id = data["id"]
-
- if id:
- job = Identifiable(data["id"])
- href = self.frame.job.get_href(session, job)
- content = fmt_shorten(data[self.name], 12, 3)
- return fmt_link(href, content)
-
- class StatusColumn(SqlTableColumn):
- def render_title(self, session, data):
return "Status"
def render_content(self, session, data):
- stat = data["job_status"]
- return JobStatusInfo.get_status_string(stat)
+ stat = data[self.name]
+ return JobStatusInfo.get_status_string(int(stat))
- class AccountingGroupColumn(SqlTableColumn):
+ class CommandColumn(QmfTableColumn):
def render_title(self, session, data):
- return "Accounting Group"
-
- class SubmitterColumn(SqlTableColumn):
- def render_title(self, session, data):
- return "Submitter"
-
- def render_content(self, session, data):
- name = data["submitter"]
-
- if name:
- sub = Identifiable(data["submitter_id"])
- href = self.page.main.grid.pool.submitter.get_href \
- (session, sub)
- return fmt_link(href, fmt_shorten(name))
-
- class SchedulerColumn(SqlTableColumn):
- def render_title(self, session, data):
- return "Scheduler"
-
- def render_content(self, session, data):
- name = data["scheduler"]
-
- if name:
- sched = Identifiable(data["scheduler_id"])
- href = self.page.main.grid.pool.scheduler.get_href \
- (session, sched)
- return fmt_link(href, fmt_shorten(name))
-
- class CommandColumn(ItemTableColumn):
- def render_title(self, session, data):
return "Command"
def render_content(self, session, data):
return fmt_shorten(data[self.name], 0, 16)
- class TitleColumn(SqlTableColumn):
- def render_title(self, session, data):
- return "Title"
+ class SubmissionJob(object):
+ def __init__(self, app, name, job, submission):
+ self.job = job
+ self.submission = submission
+ def get(self, session):
+ return (self.job.get(session), self.submission.get(session))
+
class TopJobSet(TopTable):
def __init__(self, app, name):
super(TopJobSet, self).__init__(app, name)
@@ -469,6 +377,9 @@
self.object = JobParameter(app, "id")
self.add_parameter(self.object)
+ self.scheduler = SchedulerParameter(app, "scheduler")
+ self.add_parameter(self.scheduler)
+
self.view = JobView(app, "view")
self.add_mode(self.view)
@@ -493,20 +404,23 @@
frame.set_object(session, system)
return self.page.set_frame(session, frame)
+ def get_href(self, session, job, scheduler):
+ branch = session.branch()
+ self.show_object(branch, job)
+ self.scheduler.set(session, scheduler)
+ return branch.marshal()
+
class JobView(CuminView):
def __init__(self, app, name):
super(JobView, self).__init__(app, name)
- summary = CuminSummary(app, "summary")
- self.add_child(summary)
-
self.tabs = TabbedModeSet(app, "tabs")
self.add_child(self.tabs)
self.tabs.add_tab(JobAdsViewer(app, "jobads"))
self.tabs.add_tab(JobOutput(app, "output"))
- self.tabs.add_tab(JobSystemSet(app, "systems"))
- self.tabs.add_tab(CuminDetails(app, "details"))
+ #self.tabs.add_tab(JobSystemSet(app, "systems"))
+ #self.tabs.add_tab(CuminDetails(app, "details"))
class JobSystemSet(SystemSet):
def get_args(self, session):
@@ -534,23 +448,32 @@
def get_args(self, session):
return self.frame.get_args(session)
- def do_get_items(self, session, job):
+ def do_get_items(self, session, job, scheduler):
items = self.items.get(session)
if not items:
- items = self.gen_items(session, job)
+ items = self.gen_items(session, job, scheduler)
# cache the items
self.items.set(session, items)
return items
- def get_raw_ads(self, session, job):
- action = self.app.model.job.getad
- return action.do_invoke(job)
+ def get_raw_ads(self, session, job, scheduler):
+ if not scheduler:
+ schedulers = Scheduler.select()
+ for sched in schedulers:
+ if sched.statsCurr:
+ if sched.statsCurr.TotalRunningJobs:
+ scheduler = sched
+ break
- def gen_items(self, session, job):
- job_ads = self.get_raw_ads(session, job)
+ if scheduler:
+ action = self.app.model.scheduler.GetAd
+ return action.qmfcall(scheduler, job.id)
- cls = self.app.model.get_class_by_object(job)
+ def gen_items(self, session, job, scheduler):
+ job_ads = self.get_raw_ads(session, job, scheduler)
+
+ cls = self.app.model.job
return [self.gen_item(x, job_ads[x]["VALUE"], cls, dtype=self.types[job_ads[x]["TYPE"]]) for x in job_ads]
# list of dictionaries
# each disctionary has:
@@ -631,7 +554,7 @@
groups = self.app.model.get_ad_groups()
writer = Writer()
for group in groups:
- self.group_tmpl.render(writer, session, (job, group,))
+ self.group_tmpl.render(writer, session, (job, group))
return writer.to_string()
def render_group_name(self, session, args):
@@ -676,7 +599,8 @@
group = args[1]
group_items = list()
if job:
- all_items = super(JobAdsViewer, self).do_get_items(session, job)
+ scheduler = self.frame.scheduler.get(session)
+ all_items = super(JobAdsViewer, self).do_get_items(session, job, scheduler)
for item in all_items:
if "property" in item:
property = item["property"]
@@ -698,16 +622,20 @@
self.item_renderer = EditablePropertyRenderer(self, "property_html")
+ def get_args(self, session):
+ return tuple()
+
def do_get_items(self, session, args):
job = args[0]
group = args[1]
- cls = self.app.model.get_class_by_object(job)
+ cls = self.app.model.job
ads = self.ads.get(session)
if len(ads):
return [self.gen_item(x, ads[x]["value"], cls, path=self.ads.path,
dtype=ads[x]["type"], error=ads[x], orig=ads[x]["orig"]) for x in ads
if self.is_group(x, cls, group)]
else:
+ scheduler = self.frame.scheduler.get(session)
items = super(JobAdsEditor, self).do_get_items(session, args)
for item in items:
item["path"] = self.ads.path
@@ -721,13 +649,13 @@
item_group = "Other"
return item_group == group
- def process_cancel(self, session, job):
+ def process_cancel(self, session):
branch = session.branch()
self.ads.set(branch, None) # otherwise url is too long
self.frame.view.show(branch)
self.page.set_redirect_url(session, branch.marshal())
- def process_submit(self, session, job):
+ def process_submit(self, session):
ads = self.ads.get(session)
errors = False
@@ -765,11 +693,46 @@
just_ads[unicode(field)] = fval
if not errors:
+ scheduler = self.frame.scheduler.get(session)
+ job = self.frame.get_object(session)
+ task = main.module.job_setattribute
for field in just_ads:
- action = self.app.model.job.setattribute
- action.invoke(job, [field, just_ads[field]])
- self.process_cancel(session, job)
+ task.invoke(session, job.id, field, just_ads[field], scheduler)
+ self.process_cancel(session)
+class OutputFile(Widget):
+ def __init__(self, app, name, which_file, first_last):
+ super(OutputFile, self).__init__(app, name)
+
+ self.which_file = which_file
+ self.first_last = first_last
+
+ self.defer_enabled = True
+
+ def render_content(self, session):
+ scheduler = self.frame.scheduler.get(session)
+ job = self.frame.get_object(session)
+ file, start, end = self.get_file_args(session)
+ if file:
+ action = self.app.model.scheduler.Fetch
+ data = action.qmfcall(scheduler, job, file, start, end)
+ return escape_entity(data)
+
+ def get_file_args(self, session):
+ first_last = self.first_last.get(session)
+ if first_last == "t":
+ start = -2048
+ end = 0
+ else:
+ start = 0
+ end = 2048
+ file = self.which_file.get_current_file_name(session)
+ return (file, start, end)
+
+ def render_loading(self, session, *args):
+ file = self.which_file.get_current_file_name(session)
+ return file and "loading..." or "Output, Error, and UserLog file names are invalid."
+
class JobOutput(Form):
def __init__(self, app, name):
super(JobOutput, self).__init__(app, name)
@@ -783,29 +746,42 @@
self.__fetch = self.FetchButton(app, "refresh")
self.add_child(self.__fetch)
- self.output = self.OutputFile(app, "job_output")
+ self.output = OutputFile(app, "job_output", self.which_file, self.first_last)
self.add_child(self.output)
+ self.ads = JobAdsSet(app, "ads")
+
def get_args(self, session):
return self.frame.get_args(session)
def render_title(self, session, *args):
return "Output"
- def do_render(self, session, *args):
+ def render_is_tail(self, session, *args):
+ tail = self.first_last.get(session)
+ return tail == "t" and "1" or "0"
+
+ def render_out_time(self, session, *args):
+ now = datetime.now()
+ return fmt_datetime(now, sec=True)
+
+ def do_process(self, session, *args):
job = args[0]
- out_file = job.Out
- user_file = job.UserLog
- # get err_file from JobAd
+
+ out_file = None
+ user_file = None
err_file = None
- if job.Ad:
- try:
- if "Err" in job.Ad:
- err_file = job.Ad["Err"]["VALUE"]
- err_file = strip_string_quotes(err_file)
- except Exception, e:
- pass
+ scheduler = self.frame.scheduler.get(session)
+ ads = self.ads.do_get_items(session, job, scheduler)
+ for ad in ads:
+ if ad['name'] == "Out":
+ out_file = ad['value']
+ elif ad['name'] == "UserLog":
+ user_file = ad['value']
+ elif ad['name'] == "Err":
+ err_file = ad['value']
+
# set title for radiotab so mouseover will display file name
self.which_file.set_file_name(session, "o", out_file)
self.which_file.set_file_name(session,"e", err_file)
@@ -818,37 +794,8 @@
if self.which_file.is_bad(user_file):
self.which_file.disable(session, "u")
- return super(JobOutput, self).do_render(session, *args)
+ return super(JobOutput, self).do_process(session, *args)
- def render_loading(self, session, *args):
- file = self.which_file.get_current_file_name(session)
- return file and "loading..." or "Output, Error, and UserLog file names are invalid."
-
- def get_file_args(self, session):
- first_last = self.first_last.get(session)
- if first_last == "t":
- start = -2048
- end = 0
- else:
- start = 0
- end = 2048
- file = self.which_file.get_current_file_name(session)
- return (file, start, end)
-
- class OutputFile(AjaxField):
- def get_url(self, session):
- job = self.parent.frame.get_args(session)[0]
- if job:
- file, start, end = self.parent.get_file_args(session)
- if file:
- fl = self.parent.first_last.get(session)
- args = "%s&%i&%i&%s" % (file, start, end, fl)
- args = escape_amp(args)
- return "call.xml?class=job;id=%i;method=fetch;xargs=%s" % (job.id, args)
-
- def do_render(self, session):
- return self.render_script(session)
-
class FetchButton(FormButton):
def render_content(self, session):
return "Refresh"
@@ -999,6 +946,9 @@
self.reason = self.ReasonField(app, "reason")
self.add_field(self.reason)
+ self.scheduler = SchedulerParameter(app, "scheduler")
+ self.add_parameter(self.scheduler)
+
def init(self):
assert self.object
super(JobReasonForm, self).init()
@@ -1010,23 +960,26 @@
return "Cancel"
def process_submit(self, session):
- object = self.object.get(session)
+ job = self.object.get(session)
reason = self.get_reason(session, self.verb)
+ scheduler = self.scheduler.get(session)
if not reason:
error = FormError("Reason is required")
self.errors.add(session, error)
if not self.errors.get(session):
- self.task.invoke(session, object, reason)
- self.task.exit_with_redirect(session, object)
+ self.task.invoke(session, job, reason, scheduler)
+ self.task.exit_with_redirect(session, job)
def get_reason(self, session, verb):
""" returns <verb> by username[: <user input reason>] """
- reason = [self.reason.get(session)]
- verb_by = "%s by %s" % (verb, session.user_session.subject.name)
- reason.insert(0, verb_by)
- return ": ".join(reason)
+ reason = self.reason.get(session)
+ if reason:
+ reason = [reason]
+ verb_by = "%s by %s" % (verb, session.user_session.subject.name)
+ reason.insert(0, verb_by)
+ return ": ".join(reason)
class ReasonField(StringField):
def render_title(self, session):
@@ -1060,12 +1013,12 @@
def __init__(self, app, name):
super(JobStatusSwitch, self).__init__(app, name)
- self.add_state("a", "All")
- self.add_state("r", "Running")
- self.add_state("i", "Idle")
- self.add_state("h", "Held")
- self.add_state("c", "Completed")
- self.add_state("d", "Removed")
+ self.add_state("All", "All")
+ self.add_state("Running", "Running")
+ self.add_state("Idle", "Idle")
+ self.add_state("Held", "Held")
+ self.add_state("Completed", "Completed")
+ self.add_state("Removed", "Removed")
def get_sql_constraint(self, session, phase=None):
if not phase:
@@ -1098,30 +1051,3 @@
return sql
-class JobStatusInfo(object):
- stat_strings = ["Unexpanded", "Idle", "Running", "Removed", "Completed", "Held", "Submission Error"]
- stat_colors = ["red", "clear", "green", "black", "blue", "yellow", "red"]
- @classmethod
- def get_status_string(cls, stat):
- try:
- return cls.stat_strings[stat]
- except:
- return ""
-
- @classmethod
- def get_status_color(cls, stat):
- try:
- return cls.stat_colors[stat]
- except:
- return "red"
-
- @classmethod
- def get_status_int(cls, stat):
- try:
- return cls.stat_strings.index(stat)
- except:
- return -1
-
- @classmethod
- def get_zipped_colors(cls):
- return zip(cls.stat_strings, cls.stat_colors)
Modified: mgmt/trunk/cumin/python/cumin/grid/job.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/job.strings 2009-08-25 15:20:11 UTC (rev 3587)
+++ mgmt/trunk/cumin/python/cumin/grid/job.strings 2009-08-25 22:28:04 UTC (rev 3588)
@@ -226,7 +226,7 @@
</form>
[JobOutput.css]
-textarea#job_output {
+textarea.job_output {
height: 25em;
width: 100%;
border: 1px solid #EAEAEA;
@@ -253,12 +253,11 @@
}
}
-function outputEnd() {
- var tarea = document.getElementById("job_output");
+function outputEnd(id) {
+ var tarea = $(id).getElement("textarea");
if (tarea) {
scrollToEnd(tarea);
- setTimeout("get_job_output()", 5000);
}
}
@@ -266,48 +265,38 @@
<form id="{id}" style="width:100%; border:0px;" class="mform" method="post" action="?">
<div class="out_actions">
<div class="rfloat">{first_last}</div>
-
{file}
</div>
- <div class="sactions refresh_info">{refresh} <h2>Last refresh was at <span id="out_time"></span></h2></div>
+ <div class="sactions refresh_info">{refresh} <h2>Last refresh was at {out_time}</h2></div>
<div>
- <textarea name="job_output" id="job_output" rows="20" cols="80">
- {loading}{job_output}
- </textarea>
-
+ {job_output}
{hidden_inputs}
</div>
</form>
-
-[OutTime.javascript]
-function got_out_time(obj, id) {
- var elem = document.getElementById(id);
-
- if (elem) {
- var str = obj.time.value;
- elem.innerHTML = str;
+<script type="text/javascript">
+<![CDATA[
+(function() {
+ var scrolled = false;
+ if ({is_tail}) {
+ wooly.addPageUpdateListener( function () {
+ if (!scrolled) {
+ outputEnd('{id}');
+ scrolled = true;
+ }
+ } );
}
-}
+}())
+]]>
+</script>
-[OutputFile.javascript]
-function got_job_output(obj, id) {
- var elem = document.getElementById(id);
+[OutputFile.html]
+<textarea id="{id}" name="job_output" class="job_output" rows="20" cols="80">
+ {content}
+</textarea>
- if (elem) {
- var str = obj.fetch.output;
- elem.value = str;
-
- if (obj.fetch.tail == "t") {
- outputEnd();
- }
-
- var d = new Date();
- var out_time = document.getElementById("out_time");
-
- if (out_time) {
- out_time.innerHTML = d.toLocaleString();
- }
- }
-}
+[OutputFile.deferred_html]
+<textarea id="{id}" name="job_output" class="job_output" rows="20" cols="80">
+ {loading}
+</textarea>
Modified: mgmt/trunk/cumin/python/cumin/grid/main.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/main.py 2009-08-25 15:20:11 UTC (rev 3587)
+++ mgmt/trunk/cumin/python/cumin/grid/main.py 2009-08-25 22:28:04 UTC (rev 3588)
@@ -20,6 +20,7 @@
self.job_set_release = JobSetReleaseTask(app, job)
self.job_remove = JobRemoveTask(app, job)
self.job_set_remove = JobSetRemoveTask(app, job)
+ self.job_setattribute = JobSetattributeTask(app, job)
scheduler = app.model.scheduler
self.scheduler_start = SchedulerStartTask(app, scheduler)
Modified: mgmt/trunk/cumin/python/cumin/grid/model.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/model.py 2009-08-25 15:20:11 UTC (rev 3587)
+++ mgmt/trunk/cumin/python/cumin/grid/model.py 2009-08-25 22:28:04 UTC (rev 3588)
@@ -277,29 +277,41 @@
self.form = form
self.verb = verb
+ def get_href(self, session, object):
+ fsession = self.enter(session, object)
+ #XXX fix this. what happens if this is called from the overview or inventory tab?
+ scheduler = self.cls.frame.scheduler.get(session)
+ self.form.scheduler.set(fsession, scheduler)
+ return fsession.marshal()
+
def do_enter(self, session, job):
self.form.object.set(session, job)
def do_exit(self, session, job):
- self.app.main_page.main.grid.job.view.show(session)
+ self.app.main_page.main.grid.pool.job.view.show(session)
def get_title(self, session):
return self.verb
class JobSetBaseTask(SetTask):
- def do_enter(self, session, jobs):
- self.form.object.set(session, jobs)
+ def get_href(self, session, object):
+ job, submission = object
+ fsession = self.enter(session, job)
+ self.form.scheduler.set(fsession, submission.scheduler)
+ return fsession.marshal()
+ def do_enter(self, session, job):
+ self.form.object.set(session, job)
+
class JobHoldTask(JobBaseTask):
def __init__(self, app, cls):
form = JobTaskForm(app, "job_hold", self, "Hold")
super(JobHoldTask, self).__init__(app, cls, form, "Hold")
- def do_invoke(self, completion, session, job, reason):
- assert isinstance(job, Job)
+ def do_invoke(self, completion, session, job, reason, scheduler):
+ assert isinstance(scheduler, Scheduler)
+ scheduler.Hold(self.app.model.mint.model, completion, job, reason)
- job.Hold(self.app.model.mint.model, completion, reason)
-
class JobSetHoldTask(JobSetBaseTask):
def __init__(self, app, cls):
super(JobSetHoldTask, self).__init__(app, cls)
@@ -312,11 +324,10 @@
form = JobTaskForm(app, "job_release", self, "Release")
super(JobReleaseTask, self).__init__(app, cls, form, "Release")
- def do_invoke(self, completion, session, job, reason):
- assert isinstance(job, Job)
+ def do_invoke(self, completion, session, job, reason, scheduler):
+ assert isinstance(scheduler, Scheduler)
+ scheduler.Release(self.app.model.mint.model, completion, job, reason)
- job.Release(self.app.model.mint.model, completion, reason)
-
class JobSetReleaseTask(JobSetBaseTask):
def __init__(self, app, cls):
super(JobSetReleaseTask, self).__init__(app, cls)
@@ -329,11 +340,10 @@
form = JobTaskForm(app, "job_remove", self, "Remove")
super(JobRemoveTask, self).__init__(app, cls, form, "Remove")
- def do_invoke(self, completion, session, job, reason):
- assert isinstance(job, Job)
+ def do_invoke(self, completion, session, job, reason, scheduler):
+ assert isinstance(scheduler, Scheduler)
+ scheduler.Remove(self.app.model.mint.model, completion, job, reason)
- job.Remove(self.app.model.mint.model, completion, reason)
-
class JobSetRemoveTask(JobSetBaseTask):
def __init__(self, app, cls):
super(JobSetRemoveTask, self).__init__(app, cls)
@@ -341,6 +351,18 @@
self.form = JobSetTaskForm(app, "job_set_remove", self, "Remove")
self.item_task = JobRemoveTask(app, cls)
+class JobSetattributeTask(QmfTask):
+ def __init__(self, app, cls):
+ super(JobSetattributeTask, self).__init__(app, cls)
+ self.navigable = False
+
+ def do_invoke(self, completion, session, job, name, value, scheduler):
+ assert isinstance(scheduler, Scheduler)
+ scheduler.SetAttribute(self.app.model.mint.model, completion, job, name, str(value))
+
+ def get_title(self, session):
+ return "Set Job Attribute"
+
class NegotiatorGroupTask(QmfTask):
def __init__(self, app, cls):
super(NegotiatorGroupTask, self).__init__(app, cls)
Modified: mgmt/trunk/cumin/python/cumin/grid/slot.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/slot.py 2009-08-25 15:20:11 UTC (rev 3587)
+++ mgmt/trunk/cumin/python/cumin/grid/slot.py 2009-08-25 22:28:04 UTC (rev 3588)
@@ -41,7 +41,7 @@
col = self.LoadAvgColumn(app, "load_avg")
self.add_column(col)
- col = self.JobColumn(app, "jid")
+ col = self.JobColumn(app, "job_id")
self.add_column(col)
class NameColumn(SqlTableColumn):
@@ -61,26 +61,27 @@
def render_title(self, session, data):
return "State"
- class StateColumn(SqlTableColumn):
- def render_title(self, session, data):
- return "State"
-
class LoadAvgColumn(SqlTableColumn):
def render_title(self, session, data):
return "Load"
def render_value(self, session, value):
- return "%2.02f" % value
+ if value:
+ return "%2.02f" % value
+ else:
+ return fmt_none_brief()
class JobColumn(SqlTableColumn):
def render_title(self, session, data):
return "Current Job"
def render_content(self, session, data):
- if data["jid"]:
- job = Identifiable(data["jid"])
- href = self.page.main.grid.pool.job.get_href(session, job)
- return fmt_link(href, data["job_id"])
+ if data[self.name]:
+ job = Identifiable(data[self.name])
+ pool = self.frame.get_object(session)
+ scheduler = Scheduler.select("pool='%s'" % pool.id)[0]
+ href = self.page.main.grid.pool.job.get_href(session, job, scheduler)
+ return fmt_link(href, data[self.name])
def render_items(self, session, *args):
""" overridden because a slotset query is expensive.
Modified: mgmt/trunk/cumin/python/cumin/grid/submission.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/submission.py 2009-08-25 15:20:11 UTC (rev 3587)
+++ mgmt/trunk/cumin/python/cumin/grid/submission.py 2009-08-25 22:28:04 UTC (rev 3588)
@@ -2,6 +2,7 @@
from cumin.widgets import *
from cumin.util import *
+from job import JobSet
import main
@@ -108,12 +109,7 @@
self.jobs = SubmissionJobSet(app, "jobs", submission)
self.tabs.add_tab(self.jobs)
-class SubmissionJobSet(Widget):
- def __init__(self, app, name, submission):
- super(SubmissionJobSet, self).__init__(app, name)
-
- self.submission = submission
-
+class SubmissionJobSet(JobSet):
def render_title(self, session):
return "Jobs"
Modified: mgmt/trunk/cumin/python/cumin/inventory/system.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/inventory/system.py 2009-08-25 15:20:11 UTC (rev 3587)
+++ mgmt/trunk/cumin/python/cumin/inventory/system.py 2009-08-25 22:28:04 UTC (rev 3588)
@@ -145,7 +145,7 @@
def render_slot_job_url(self, session):
job = Identifiable("XXX")
- return self.page.main.grid.pool.job.get_href(session, job)
+ return self.page.main.grid.pool.job.get_href(session, job, None)
class SystemSlotMap(SlotMap):
def get_title_name(self, session, sysimage):
@@ -165,7 +165,7 @@
self.add_child(self.__tabs)
self.__tabs.add_tab(SystemStats(app, "stats"))
- self.__tabs.add_tab(SystemJobSet(app, "jobs", None))
+ #self.__tabs.add_tab(SystemJobSet(app, "jobs", submission))
self.__tabs.add_tab(SystemSlotSet(app, "slots"))
self.__tabs.add_tab(SystemServices(app, "services"))
self.__tabs.add_tab(CuminDetails(app, "details"))
@@ -246,7 +246,8 @@
brokers = Broker.select()
for broker in brokers:
if broker.system.nodeName == system.nodeName:
- daemons.append(BrokerRegistration.get(broker.registrationID))
+ if broker.registrationID:
+ daemons.append(BrokerRegistration.get(broker.registrationID))
return daemons
@@ -258,7 +259,7 @@
else:
pool = model.Pool.get(item.Pool)
self.page.main.grid.pool.object.set(session, pool)
- self.page.main.show_grid_tab(session)
+ #self.page.main.show_grid_tab(session)
daemon = Identifiable(item.id)
if isinstance(item, Collector):
self.page.main.grid.pool.view.set_collector_tab(session)
Modified: mgmt/trunk/cumin/python/cumin/model.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/model.py 2009-08-25 15:20:11 UTC (rev 3587)
+++ mgmt/trunk/cumin/python/cumin/model.py 2009-08-25 22:28:04 UTC (rev 3588)
@@ -384,7 +384,7 @@
return value
class AdProperty(CuminProperty):
- groups = ["Main", "Command Info", "Job Status Info", "Condor Info", "Other"]
+ groups = ["Main", "Command Info", "Job Status Info", "Condor Info", "Dates", "Other"]
def __init__(self, cls, name):
# don't call super since we don't want to call add_property
@@ -1899,9 +1899,19 @@
def get_icon_href(self, session):
return "resource?name=group-36.png"
-class CuminJob(RemoteClass):
+class Job(object):
+ def __init__(self, id):
+
+ self.id = id
+ self.name = id
+
+ def get(cls, id):
+ return Job(id)
+ get = classmethod(get)
+
+class CuminJob(CuminClass):
def __init__(self, model):
- super(CuminJob, self).__init__(model, "job", Job, JobStats)
+ super(CuminJob, self).__init__(model, "job", Job)
### Main Group
prop = AdProperty(self, "Owner")
@@ -1979,47 +1989,60 @@
prop = DateAdProperty(self, "QDate")
prop.description = "When the job was submitted"
+ prop.group = "Dates"
prop.writable = False
+ prop = DateAdProperty(self, "LastVacateTime")
+ prop.group = "Dates"
+ prop.writable = False
+
prop = DateAdProperty(self, "JobStartDate")
prop.group = "Main"
prop.writable = False
prop = DateAdProperty(self, "JobCurrentStartDate")
+ prop.group = "Dates"
prop.writable = False
+ prop = DateAdProperty(self, "JobLastStartDate")
+ prop.group = "Dates"
+ prop.writable = False
+
prop = DateAdProperty(self, "LastSuspensionTime")
+ prop.group = "Dates"
prop.writable = False
prop = DateAdProperty(self, "ShadowBday")
+ prop.group = "Dates"
prop.writable = False
prop = DateAdProperty(self, "LastJobLeaseRenewal")
+ prop.group = "Dates"
prop.writable = False
prop = DateAdProperty(self, "EnteredCurrentStatus")
+ prop.group = "Dates"
prop.writable = False
prop = DateAdProperty(self, "CommittedTime")
+ prop.group = "Dates"
prop.writable = False
prop = DateAdProperty(self, "LastMatchTime")
+ prop.group = "Dates"
prop.writable = False
######## Properties
- prop = self.GroupProperty(self, "CustomGroup")
+ prop = CuminProperty(self, "CustomGroup")
prop.title = "Job Group"
- prop.summary = True
prop.escape = False
- prop = self.SchedulerProperty(self, "scheduler")
+ prop = CuminProperty(self, "scheduler")
prop.title = "Scheduler"
- prop.summary = True
prop.escape = False
- prop = self.SubmitterProperty(self, "submitter")
+ prop = CuminProperty(self, "submitter")
prop.title = "Submitter"
- prop.summary = True
prop.escape = False
prop = CuminProperty(self, "AccountingGroup")
@@ -2070,15 +2093,6 @@
prop = CuminProperty(self, "HoldReason")
prop.title = "Hold Reason"
- action = self.SetAttribute(self, "setattribute")
- action.navigable = False
-
- action = self.GetAd(self, "getad")
- action.navigable = False
-
- action = self.Fetch(self, "fetch")
- action.navigable = False
-
def init(self):
super(CuminJob, self).init()
@@ -2088,7 +2102,10 @@
return "Job"
def get_object_name(self, job):
- return job.CustomId
+ if isinstance(job, basestring):
+ return job
+ else:
+ return job.name
def get_icon_href(self, session):
return "resource?name=job-36.png"
@@ -2097,102 +2114,6 @@
def render_status(self, session, status):
return JobStatusInfo.get_status_string(status)
- class GroupProperty(CuminProperty):
- def value(self, session, job):
- group = JobGroup(job.CustomGroup)
- href = self.model.frame.grid.pool.job_group.get_href \
- (session, group)
- content = fmt_shorten(group.id, 12, 3)
- return fmt_link(href, group.get_id())
-
- class SubmitterProperty(CuminProperty):
- def value(self, session, job):
- sub = job.submitter
- href = self.model.frame.grid.pool.submitter.get_href(session, sub)
- return fmt_link(href, sub.Name)
-
- class SchedulerProperty(CuminProperty):
- def value(self, session, job):
- sched = job.scheduler
- href = self.model.frame.grid.pool.scheduler.get_href \
- (session, sched)
- return fmt_link(href, sched.Name)
-
- class GetAd(CuminAction):
- def do_invoke(self, job):
- self.job_ads = {"":{"VALUE": "", "TYPE": 0}}
- self.got_data = False
-
- def completion(status, job_ads):
- try:
- self.job_ads = job_ads["JobAd"]
- self.got_data = True
- except:
- pass
-
- def predicate():
- return self.got_data
-
- try:
- job.GetAd(self.mint.model, completion, None)
- except Exception, e:
- return self.job_ads
-
- # wait for up to 20 seconds for completion to be called
- wait(predicate, timeout=20)
- return self.job_ads
-
- class Fetch(CuminAction):
- def get_xml_response(self, session, job, *args):
- file, start, end, tail = args
- self.job_output = None
- self.got_data = False
- self.reason = None
-
- def completion(status, job_output):
- if "Data" in job_output:
- raw = job_output["Data"]
- #remove the last partial line from the buffer
- lindex = -1
- ord_nl = ord('\n')
- while ord(raw[-lindex:][0]) != ord_nl:
- lindex = lindex + 1
- self.job_output = raw[:-lindex]
- else:
- self.reason = status
-
- self.got_data = True
-
- def predicate():
- return self.got_data
-
- try:
- data = None
- job.Fetch(self.mint.model, completion, file, start, end, data)
- # wait for up to 20 seconds for completion to be called
- wait(predicate, timeout=20)
- if not self.got_data:
- self.reason = "time out"
- except Exception, e:
- self.reason = e
-
- if self.reason:
- self.job_output = "Unable to get file at %s. Reason: %s" % (file, self.reason)
-
- return self.job_output and "<fetch><output>%s</output><tail>%s</tail></fetch>" % (escape_entity(self.job_output), tail)
-
- class SetAttribute(CuminAction):
- def show(self, session, job):
- pass
-
- def get_title(self, session):
- return "Save Ad for"
-
- def do_invoke(self, job, args, completion):
- Name = args[0]
- Value = args[1]
- job.SetAttribute(self.mint.model, completion, Name, str(Value))
-
class GetStartedAction(CuminAction):
def get_xml_response(self, session, object, *args):
updateTime = object.statsCurr and object.statsCurr.qmfUpdateTime \
@@ -2203,6 +2124,27 @@
return "%s%s" % (conf, rect)
+class QMFCaller(object):
+ def __init__(self, default):
+ self.data = default
+ self.got_data = False
+ self.error = False
+ self.status = None
+
+ def get_completion(self):
+ def completion(status, data):
+ self.status = status
+ if (status == 0) or (status == "OK"):
+ self.data = data
+ self.got_data = True
+ else:
+ self.error = True
+
+ return completion
+
+ def done(self):
+ return self.got_data or self.error
+
class CuminScheduler(RemoteClass):
def __init__(self, model):
super(CuminScheduler, self).__init__(model, "scheduler",
@@ -2251,6 +2193,15 @@
action = GetStartedAction(self, "GetStarted")
action.navigable = False
+ action = self.GetJobs(self, "GetJobs")
+ action.navigable = False
+
+ action = self.GetAd(self, "GetAd")
+ action.navigable = False
+
+ action = self.Fetch(self, "Fetch")
+ action.navigable = False
+
def init(self):
super(CuminScheduler, self).init()
@@ -2262,6 +2213,35 @@
def get_object_name(self, sched):
return sched.Name
+ class Fetch(CuminAction):
+ def qmfcall(self, scheduler, job, file, start, end):
+ default = {'Data': ""}
+ qmf = QMFCaller(default)
+ scheduler.Fetch(self.mint.model, qmf.get_completion(), job.id, file, start, end, None)
+ wait(qmf.done, timeout=10)
+
+ return qmf.data['Data']
+
+ class GetAd(CuminAction):
+ def qmfcall(self, scheduler, job):
+
+ default = {'JobAd': {"":{"VALUE":"", "TYPE":0}}}
+ qmf = QMFCaller(default)
+ scheduler.GetAd(self.mint.model, qmf.get_completion(), job, None)
+ wait(qmf.done, timeout=10)
+
+ return qmf.data['JobAd']
+
+ class GetJobs(CuminAction):
+ def qmfcall(self, scheduler, submission):
+
+ default = {'Jobs': {}}
+ qmf = QMFCaller(default)
+ scheduler.GetJobs(self.mint.model, qmf.get_completion(), submission, None)
+ wait(qmf.done, timeout=10)
+
+ return qmf.data['Jobs']
+
class CuminSubmission(RemoteClass):
def __init__(self, model):
super(CuminSubmission, self).__init__(model, "submission",
@@ -2433,29 +2413,15 @@
class GetRawConfig(CuminAction):
def do_invoke(self, negotiator, config_name, timeout=5):
- self.data = None
- self.got_data = False
- self.error = False
+ default = {'Value': ""}
+ qmf = QMFCaller(default)
+ negotiator.GetRawConfig(self.mint.model, qmf.get_completion(), config_name, None)
+ wait(qmf.done, timeout=timeout)
+ return qmf.data
- def completion(status, data):
- self.data = data
- self.got_data = True
-
- def predicate():
- return self.got_data or self.error
-
- try:
- negotiator.GetRawConfig(self.mint.model, completion, config_name, None)
- except Exception, e:
- self.error = True
-
- wait(predicate, timeout=timeout)
- return self.data
-
class GetConfigSet(CuminAction):
- """ send a set or qmf requests at the same time and wait for
+ """ send a set of qmf requests at the same time and wait for
them all to complete or timeout """
-
def do_invoke(self, negotiator, groups, prepend="", method="GetStats", timeout=5):
def predicate(calls):
done = 0
@@ -2465,70 +2431,31 @@
return done == len(calls)
calls = list()
+ default = {'Value': 0}
for group in groups:
- call = self.StatGetter()
+ call = QMFCaller(default)
calls.append(call)
- call.invoke(self.mint.model, negotiator, group, prepend, method, {'Value': 0})
+ if method == "GetStats":
+ negotiator.GetStats(self.mint.model, call.get_completion(), group, None)
+ elif method == "GetRawConfig":
+ negotiator.GetRawConfig(self.mint.model, call.get_completion(), prepend+group, None)
wait(predicate, timeout=timeout, args=calls)
- return [(call.group, call.data, (call.status, call.error, call.got_data))
- for call in calls]
+ return [(group, call.data, (call.status, call.error, call.got_data))
+ for call, group in zip(calls, groups)]
- class StatGetter(object):
- def invoke(self, model, negotiator, group, prepend, method, default):
- self.data = default
- self.group = group
- self.got_data = False
- self.error = False
- self.status = None
-
- def completion(status, data):
- self.status = status
- if (status == 0) or (status == "OK"):
- self.data = data
- self.got_data = True
- else:
- self.error = True
-
- try:
- if method == "GetStats":
- negotiator.GetStats(model, completion, group, None)
- elif method == "GetRawConfig":
- negotiator.GetRawConfig(model, completion, prepend+group, None)
- except Exception, e:
- self.error = True
-
- def done(self):
- return self.got_data or self.error
-
class GetLimits(CuminAction):
def do_invoke(self, negotiator):
- self.lim = dict()
- self.got_data = False
- self.error = False
+ default = {'Limits': {}}
+ qmf = QMFCaller(default)
+ negotiator.GetLimits(self.mint.model, qmf.get_completion(), None)
+ wait(qmf.done, timeout=2)
- def completion(status, data):
- try:
- self.lim = data["Limits"]
- self.got_data = True
- except KeyError:
- self.error = True
+ if not qmf.got_data:
+ return {'timeout': True}
+ return qmf.data['Limits']
- def predicate():
- return self.got_data or self.error
-
- try:
- negotiator.GetLimits(self.mint.model, completion, None)
- except Exception, e:
- return self.lim
-
- # wait a couple of seconds for completion to be called
- wait(predicate, timeout=2)
- if not self.got_data:
- self.lim["timeout"] = True
- return self.lim
-
class CuminSubject(CuminClass):
def __init__(self, model):
super(CuminSubject, self).__init__(model, "subject", Subject)
Modified: mgmt/trunk/cumin/python/cumin/parameters.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/parameters.py 2009-08-25 15:20:11 UTC (rev 3587)
+++ mgmt/trunk/cumin/python/cumin/parameters.py 2009-08-25 22:28:04 UTC (rev 3588)
@@ -78,10 +78,12 @@
class JobParameter(Parameter):
def do_unmarshal(self, string):
- return Job.get(int(string))
+ return model.Job(string)
def do_marshal(self, job):
- return str(job.id)
+ if isinstance(job, basestring):
+ return job
+ return job.id
class JobGroupParameter(Parameter):
def do_unmarshal(self, string):
Modified: mgmt/trunk/cumin/python/cumin/util.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/util.py 2009-08-25 15:20:11 UTC (rev 3587)
+++ mgmt/trunk/cumin/python/cumin/util.py 2009-08-25 22:28:04 UTC (rev 3588)
@@ -145,3 +145,31 @@
if value[:1] == "\"" and value[-1:] == "\"":
dvalue = value[1:-1]
return dvalue
+
+class JobStatusInfo(object):
+ stat_strings = ["Unexpanded", "Idle", "Running", "Removed", "Completed", "Held", "Submission Error"]
+ stat_colors = ["red", "clear", "green", "black", "blue", "yellow", "red"]
+ @classmethod
+ def get_status_string(cls, stat):
+ try:
+ return cls.stat_strings[stat]
+ except:
+ return ""
+
+ @classmethod
+ def get_status_color(cls, stat):
+ try:
+ return cls.stat_colors[stat]
+ except:
+ return "red"
+
+ @classmethod
+ def get_status_int(cls, stat):
+ try:
+ return cls.stat_strings.index(stat)
+ except:
+ return -1
+
+ @classmethod
+ def get_zipped_colors(cls):
+ return zip(cls.stat_strings, cls.stat_colors)
Modified: mgmt/trunk/cumin/python/cumin/visualizations.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/visualizations.py 2009-08-25 15:20:11 UTC (rev 3587)
+++ mgmt/trunk/cumin/python/cumin/visualizations.py 2009-08-25 22:28:04 UTC (rev 3588)
@@ -49,7 +49,15 @@
def render_slot_job_url(self, session, *args):
job = Identifiable("XXX")
- return self.page.main.grid.pool.job.get_href(session, job)
+ object = args[0]
+ try:
+ if isinstance(object, Sysimage):
+ scheduler = Scheduler.select("system='%s'" % object.nodeName)[0]
+ else:
+ scheduler = Scheduler.select("pool='%s'" % object.id)[0]
+ return self.page.main.grid.pool.job.get_href(session, job, scheduler)
+ except:
+ pass
def render_slot_clip_size(self, session, *args):
return 400
@@ -150,7 +158,8 @@
return item[1]
def render_job_id(self, session, item):
- return item[0] == "jid" and "id='job_id'" or ""
+ #return item[0] == "jid" and "id='job_id'" or ""
+ return item[0] == "Job ID" and "id='job_id'" or ""
def render_row_class(self, session, item):
return item[0] == "jid" and "class='hidden_row'" or ""
Modified: mgmt/trunk/cumin/python/cumin/visualizations.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/visualizations.strings 2009-08-25 15:20:11 UTC (rev 3587)
+++ mgmt/trunk/cumin/python/cumin/visualizations.strings 2009-08-25 22:28:04 UTC (rev 3588)
@@ -917,6 +917,7 @@
div#slot_visualization {
position: relative;
display: none;
+ float: left;
}
div.zoom_node {
@@ -1015,6 +1016,7 @@
<div id="slot_pandown" onclick="vis.pan_down()"></div>
{slot_legend}
</div>
+<div style="clear: left"><!-- --></div>
{slot_info}
<script type="text/javascript">
var slot_current_id = "{id}";
Modified: mgmt/trunk/cumin/python/cumin/widgets.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/widgets.py 2009-08-25 15:20:11 UTC (rev 3587)
+++ mgmt/trunk/cumin/python/cumin/widgets.py 2009-08-25 22:28:04 UTC (rev 3588)
@@ -682,6 +682,14 @@
cls = super(ClientTruncateColumn, self).get_class_attr(session)
return "width=\"%i%%\" %s" % (self.col_percent, cls)
+class QmfTableColumn(ItemTableColumn):
+ def render_content(self, session, data):
+ key = self.get_column_key(session)
+ return self.render_value(session, data[key])
+
+ def render_value(self, session, value):
+ return str(value)
+
class TopTableColumn(SqlTableColumn):
def __init__(self, app, name):
super(TopTableColumn, self).__init__(app, name)
@@ -830,6 +838,57 @@
self.links.html_class = "actions" # XXX fix this
self.add_child(self.links)
+class CuminQMFSelectionTable(CuminSelectionTable):
+ def filter_item(self, session, item):
+ return True
+
+ def get_item_count(self, session, *args):
+ items = self.items.get(session)
+ if not items:
+ items = self.do_get_items(session, *args)
+
+ self.items.set(session, items)
+
+ count = 0
+ for item in items:
+ if self.filter_item(session, items[item]):
+ count += 1
+ return count
+
+ def do_get_items(self, session, *args):
+ raise Exception("not implemented")
+
+ def render_items(self, session, *args):
+ items = self.get_items(session, *args)
+ rows = list()
+ for item in items:
+ data = dict()
+ # filter them
+ if self.filter_item(session, items[item]):
+ data['id'] = item
+ data['name'] = item
+ for datum in items[item]:
+ data[datum] = items[item][datum]['VALUE']
+ rows.append(data)
+
+ # sort them
+ scol = self.get_selected_column(session)
+ rows = sorted(rows, key=lambda x: x[scol.name], reverse=self.reversed.get(session))
+
+ # limit them
+ page = self.paginator.page_index.get(session)
+ items_per_page = self.paginator.page_size
+
+ start = page * items_per_page
+ stop = start + items_per_page
+ rows = rows[start:stop]
+
+ # render them
+ writer = Writer()
+ for row in rows:
+ self.item_tmpl.render(writer, session, row)
+ return writer.to_string()
+
class NullSortColumn(SqlTableColumn):
def get_order_by_sql(self, session):
key = self.get_column_key(session)
Modified: mgmt/trunk/cumin/python/cumin/widgets.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/widgets.strings 2009-08-25 15:20:11 UTC (rev 3587)
+++ mgmt/trunk/cumin/python/cumin/widgets.strings 2009-08-25 22:28:04 UTC (rev 3588)
@@ -484,6 +484,10 @@
display: inline;
}
+div.CuminTable form {
+ clear: both;
+}
+
table.CuminTable td {
text-overflow:ellipsis;
}
@@ -595,11 +599,12 @@
[CheckboxColumnHeader.javascript]
function checkAll(control_id, form_id, elem_name) {
- control = document.getElementById(control_id)
- form = document.getElementById(form_id);
+ var control = document.getElementById(control_id)
+ var div = document.getElementById(form_id);
+ var form = $(div).getElement("form");
- for (i = 0; i < form.elements.length; i++) {
- elem = form.elements[i];
+ for (var i = 0; i < form.elements.length; i++) {
+ var elem = form.elements[i];
if (elem.name == elem_name) {
if (elem.checked != control.checked)
15 years, 4 months