r4809 - trunk/cumin/python/cumin/grid
by croberts@fedoraproject.org
Author: croberts
Date: 2011-06-13 18:55:39 +0000 (Mon, 13 Jun 2011)
New Revision: 4809
Modified:
trunk/cumin/python/cumin/grid/limit.py
trunk/cumin/python/cumin/grid/limit.strings
Log:
Addressing BZ: https://bugzilla.redhat.com/show_bug.cgi?id=712968 by correctly setting the initial state of the limits input box and checkbox for the case where the initial value of the limit is unlimited. Also tweaking how we handle the disabled input display of the limit name. It will no longer look like an input box that is just not working. Instead, we display the plain text and maintain the input value with a hidden input.
Modified: trunk/cumin/python/cumin/grid/limit.py
===================================================================
--- trunk/cumin/python/cumin/grid/limit.py 2011-06-13 14:32:57 UTC (rev 4808)
+++ trunk/cumin/python/cumin/grid/limit.py 2011-06-13 18:55:39 UTC (rev 4809)
@@ -204,8 +204,20 @@
return self.input.get(session)
def render_field_name(self,session):
- return self.input.param.path
+ return self.input.param.path
+ def render_is_readonly(self, session):
+ retval = ""
+ if self.input.get(session) == "Unlimited":
+ retval = "readonly='readonly'"
+ return retval
+
+ def render_is_checked(self, session):
+ retval = ""
+ if self.input.get(session) == "Unlimited":
+ retval = "checked='checked'"
+ return retval
+
def render_checkbox_name(self,session):
return self.checkbox.param.path
Modified: trunk/cumin/python/cumin/grid/limit.strings
===================================================================
--- trunk/cumin/python/cumin/grid/limit.strings 2011-06-13 14:32:57 UTC (rev 4808)
+++ trunk/cumin/python/cumin/grid/limit.strings 2011-06-13 18:55:39 UTC (rev 4809)
@@ -13,24 +13,10 @@
}
[DisabledInput.html]
-<input class="disabled" type="text" name="{name}" id="{name}" value="{value}" tabindex="{tab_index}" size="{size}"/>
-<script type="text/javascript">
-//<![CDATA[
-// Using input attribute disabled="disabled' has the unfortunate side effect of not sending the input value
-// when the form is submitted. So we just leave it enabled and filter out keyboard input with javascript.
-window.addEvent("domready",
- function () {
- $("{name}").addEvent("keypress",
- function (e) {
- if (!(e.key in {tab:1, left:1, right:1}))
- if (! (e.key == 'c' && e.control) )
- new Event(e).stop();
- } )
- }
-);
-//]]>
-</script>
+{value}
+<input type="hidden" name="{name}" id="{name}" value="{value}" tabindex="{tab_index}" size="{size}"/>
+
[StringFieldWithCheckbox.input_with_checkbox_html]
<tr id="{id}">
<th>
@@ -38,12 +24,15 @@
<div class="help"></div>
</th>
<td>
- <input type="text" name="{field_name}" id="{field_name}" value="{field_value}" tabindex="100" size="30" />
- <input type="checkbox" name="{checkbox_name}" id="{checkbox_name}" {onclick_attr}/><label for="{checkbox_name}">Unlimited</label>
+ <input type="text" name="{field_name}" id="{field_name}" value="{field_value}" tabindex="100" size="30" {is_readonly}/>
+ <input type="checkbox" name="{checkbox_name}" id="{checkbox_name}" {onclick_attr} {is_checked}/><label for="{checkbox_name}">Unlimited</label>
</td>
</tr>
<script type="text/javascript">
//<![CDATA[
+window.addEvent('domready', function(){
+ myFunction();
+});
function toggleLimitInput(form, checkbox, textinput) {
if($(checkbox).checked) {
$(textinput).value = "Unlimited";
12 years, 11 months
r4808 - trunk/mint/python/mint
by tmckay@fedoraproject.org
Author: tmckay
Date: 2011-06-13 14:32:57 +0000 (Mon, 13 Jun 2011)
New Revision: 4808
Modified:
trunk/mint/python/mint/main.py
trunk/mint/python/mint/session.py
trunk/mint/python/mint/update.py
Log:
Delete objects of all bound classes when cumin-data starts. Does not delete sample data or data from packages explicitly excluded in mint.qmf_package_filter. This gets rid of all phantom data associated with agents not connected to the broker when cumin runs (more important now that filtering by pool has been removed).
BZ702440
Modified: trunk/mint/python/mint/main.py
===================================================================
--- trunk/mint/python/mint/main.py 2011-06-13 13:33:07 UTC (rev 4807)
+++ trunk/mint/python/mint/main.py 2011-06-13 14:32:57 UTC (rev 4808)
@@ -32,11 +32,18 @@
self.sasl_mech_list = None
# List of agents to bind. Referenced by session.
- self.qmf_agents = None
+ self.qmf_agents = set()
# List of classes to bind. Referenced by session and update thread.
- self.qmf_classes = None
+ self.qmf_classes = set()
+ # If binding was not done by class, this is the final list of
+ # packages that were bound
+ self.qmf_packages = set()
+
+ # Things we know should not be bound.
+ self.qmf_package_filter = ["com.redhat.cumin", "com.redhat.cumin.grid"]
+
def check(self):
log.info("Checking %s", self)
@@ -64,6 +71,10 @@
def start(self):
log.info("Starting %s", self)
+ # Scan the qmf class/package binding list
+ # and do any necessary preprocessing
+ self.session.init_qmf_classes()
+
self.update_thread.start()
self.session.start()
Modified: trunk/mint/python/mint/session.py
===================================================================
--- trunk/mint/python/mint/session.py 2011-06-13 13:33:07 UTC (rev 4807)
+++ trunk/mint/python/mint/session.py 2011-06-13 14:32:57 UTC (rev 4808)
@@ -27,6 +27,21 @@
def init(self):
log.info("Initializing %s", self)
+ def init_qmf_classes(self):
+ # Apply the package filter to the class list
+ if len(self.app.qmf_classes):
+ black_list = set()
+ for cls in self.app.qmf_classes:
+ if cls._package._name in self.app.qmf_package_filter:
+ black_list.add(cls)
+ self.app.qmf_classes.difference_update(black_list)
+ else:
+ # Generate the package list from the model, minus
+ # the package filter
+ for pkg in self.app.model._packages:
+ if pkg._name not in self.app.qmf_package_filter:
+ self.app.qmf_packages.add(pkg)
+
def start(self):
log.info("Starting %s", self)
@@ -39,7 +54,7 @@
rcvHeartbeats=False,
userBindings=True)
- if self.app.qmf_agents:
+ if len(self.app.qmf_agents):
for agent in self.app.qmf_agents:
if len(agent) == 1:
self.qmf_session.bindAgent(label=agent[0])
@@ -53,25 +68,19 @@
else:
self.qmf_session.bindAgent("*")
log.info("Binding all agents")
-
- # Filter out classes we know should not be bound at this point in time
- # This is to prevent confusion in log files.
- package_filter = ["com.redhat.cumin", "com.redhat.cumin.grid"]
# Handle bind by class
- if self.app.qmf_classes:
+ if len(self.app.qmf_classes):
for cls in self.app.qmf_classes:
pname = cls._package._name
cname = cls._name
- if pname not in package_filter:
- self.qmf_session.bindClass(pname.lower(), cname.lower())
- log.info("Binding QMF class %s.%s" % (pname, cname))
+ self.qmf_session.bindClass(pname.lower(), cname.lower())
+ log.info("Binding QMF class %s.%s" % (pname, cname))
else:
# Handle bind by package
- for pkg in self.app.model._packages:
- if pkg._name not in package_filter:
- self.qmf_session.bindPackage(pkg._name.lower())
- log.info("Binding QMF package %s" % pkg._name)
+ for pkg in self.app.qmf_packages:
+ self.qmf_session.bindPackage(pkg._name.lower())
+ log.info("Binding QMF package %s" % pkg._name)
for uri in self.broker_uris:
self.add_broker(uri)
Modified: trunk/mint/python/mint/update.py
===================================================================
--- trunk/mint/python/mint/update.py 2011-06-13 13:33:07 UTC (rev 4807)
+++ trunk/mint/python/mint/update.py 2011-06-13 14:32:57 UTC (rev 4808)
@@ -26,6 +26,23 @@
self.halt_on_error = False
+ def _delete_all_objects(self):
+ def loop_body(cls):
+ if cls._storage != "none":
+ cls.delete_selection(self.cursor)
+ self.cursor.connection.commit()
+
+ if len(self.app.qmf_classes):
+ log.debug("Delete all objects by bound classes " + str(self.app.qmf_classes))
+ for cls in self.app.qmf_classes:
+ loop_body(cls)
+ else:
+ # We bound all classes. Loop over model
+ log.debug("Delete all objects by bound packages " + str(self.app.qmf_packages))
+ for pkg in self.app.qmf_packages:
+ for cls in pkg._classes:
+ loop_body(cls)
+
def init(self):
self.conn = self.app.database.get_connection()
@@ -38,6 +55,8 @@
self.stats.enqueued += 1
def run(self):
+ self._delete_all_objects()
+
while True:
if self.stop_requested:
break
@@ -184,7 +203,8 @@
log.debug("Processing %s", self)
try:
- self.do_process(thread.cursor, thread.stats, thread.app.qmf_classes)
+ self.do_process(thread.cursor, thread.stats,
+ thread.app.qmf_classes, thread.app.qmf_packages)
thread.conn.commit()
except UpdateDropped:
@@ -205,7 +225,7 @@
if thread.halt_on_error:
raise
- def do_process(self, cursor, stats, bound_classes):
+ def do_process(self, cursor, stats, bound_classes, bound_packages):
raise Exception("Not implemented")
def __repr__(self):
@@ -217,7 +237,7 @@
self.qmf_object = qmf_object
- def do_process(self, cursor, stats, bound_classes):
+ def do_process(self, cursor, stats, bound_classes, bound_packages):
cls = self.get_class()
agent_id = self.get_agent_id()
object_id = self.get_object_id()
@@ -574,18 +594,14 @@
def get_agent_id(self):
return make_agent_id(self.qmf_agent)
- def do_process(self, cursor, stats, bound_classes):
+ def do_process(self, cursor, stats, bound_classes, bound_packages):
agent_id = self.get_agent_id()
try:
agent = self.model.agents_by_id[agent_id]
except KeyError:
agent = MintAgent(self.model, agent_id)
-
stats.agents_created += 1
-
- self.delete_agent_objects(cursor, stats, agent, bound_classes)
-
return
#timestamp = timestamp / 1000000000
@@ -595,7 +611,7 @@
stats.agents_updated += 1
- def delete_agent_objects(self, cursor, stats, agent, bound_classes):
+ def delete_agent_objects(self, cursor, stats, agent, bound_classes, bound_packages):
def loop_body(cls):
if cls._storage != "none" and cls is not self.model.com_redhat_grid.Collector:
@@ -604,14 +620,14 @@
#stats.objects_deleted_by_class[cls] += count
cursor.connection.commit()
- if bound_classes:
+ if len(bound_classes):
log.debug("Delete agent objects by bound classes " + str(bound_classes))
for cls in bound_classes:
loop_body(cls)
else:
# We bound all classes. Loop over model
- log.debug("Delete agent objects, all classes")
- for pkg in self.model._packages:
+ log.debug("Delete agent objects by bound packages " + str(bound_packages))
+ for pkg in bound_packages:
for cls in pkg._classes:
loop_body(cls)
@@ -622,7 +638,7 @@
return "%s(%s)" % (name, agent_id)
class AgentDelete(AgentUpdate):
- def do_process(self, cursor, stats, bound_classes):
+ def do_process(self, cursor, stats, bound_classes, bound_packages):
agent_id = self.get_agent_id()
try:
@@ -634,7 +650,7 @@
stats.agents_deleted += 1
- self.delete_agent_objects(cursor, stats, agent, bound_classes)
+ self.delete_agent_objects(cursor, stats, agent, bound_classes, bound_packages)
class UpdateDropped(Exception):
pass
12 years, 11 months
r4807 - trunk/cumin/python/cumin/grid
by tmckay@fedoraproject.org
Author: tmckay
Date: 2011-06-13 13:33:07 +0000 (Mon, 13 Jun 2011)
New Revision: 4807
Modified:
trunk/cumin/python/cumin/grid/pool.py
Log:
Additional tweaks related to removal of collector filtering
Modified: trunk/cumin/python/cumin/grid/pool.py
===================================================================
--- trunk/cumin/python/cumin/grid/pool.py 2011-06-09 16:31:16 UTC (rev 4806)
+++ trunk/cumin/python/cumin/grid/pool.py 2011-06-13 13:33:07 UTC (rev 4807)
@@ -119,6 +119,12 @@
collector = self.app.model.find_youngest(self.cls, session.cursor)
if collector:
self.id.set(session, collector._id)
+ id = collector._id
- super(PoolFrame, self).do_process(session)
+ # If we still don't have an id, skip the processing step.
+ # This avoids an assertion error in do_process
+ # When we go to render, we will get the "Missing Pool" banner
+ # from PoolView, so the user will get a nice message
+ if id:
+ super(PoolFrame, self).do_process(session)
12 years, 11 months
r4806 - in trunk/cumin/python/cumin: . grid
by tmckay@fedoraproject.org
Author: tmckay
Date: 2011-06-09 16:31:16 +0000 (Thu, 09 Jun 2011)
New Revision: 4806
Removed:
trunk/cumin/python/cumin/grid/model.py
Modified:
trunk/cumin/python/cumin/grid/main.py
trunk/cumin/python/cumin/grid/pool.py
trunk/cumin/python/cumin/widgets.py
Log:
More cleanup, fix mistakes in 4805
(BZ699413 modifications)
Modified: trunk/cumin/python/cumin/grid/main.py
===================================================================
--- trunk/cumin/python/cumin/grid/main.py 2011-06-09 14:47:07 UTC (rev 4805)
+++ trunk/cumin/python/cumin/grid/main.py 2011-06-09 16:31:16 UTC (rev 4806)
@@ -8,7 +8,7 @@
from cumin.grid.slot import SlotMapPage
from cumin.grid.slotvis import PoolSlotFullPage
-from model import *
+from submission import *
from pool import *
from test import *
Deleted: trunk/cumin/python/cumin/grid/model.py
===================================================================
--- trunk/cumin/python/cumin/grid/model.py 2011-06-09 14:47:07 UTC (rev 4805)
+++ trunk/cumin/python/cumin/grid/model.py 2011-06-09 16:31:16 UTC (rev 4806)
@@ -1,113 +0,0 @@
-from wooly import Session
-
-from cumin.model import *
-from cumin.objecttask import *
-from cumin.util import *
-
-from job import *
-from submission import *
-from scheduler import *
-from collector import *
-from negotiator import *
-
-#from cumin.model import Pool
-
-# class SeePoolsTask(Task):
-# def get_title(self, session):
-# return "See all pools"
-
-# def do_enter(self, session, scheduler):
-# self.app.main_page.grid.view.show(branch)
-
-# class JobBaseTask(QmfTask):
-# def __init__(self, app, cls, form, verb):
-# super(JobBaseTask, self).__init__(app, cls)
-
-# 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):
-# self.app.main_page.main.grid.pool.job.view.show(session)
-
-# def get_title(self, session):
-# return self.verb
-
-# class JobSetBaseTask(SetTask):
-# 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, scheduler):
-# assert isinstance(scheduler, Scheduler)
-# scheduler.Hold(completion, job, reason)
-
-# class JobSetHoldTask(JobSetBaseTask):
-# def __init__(self, app, cls):
-# super(JobSetHoldTask, self).__init__(app, cls)
-
-# self.form = JobSetTaskForm(app, "job_set_hold", self, "Hold")
-# self.item_task = JobHoldTask(app, cls)
-
-# class JobReleaseTask(JobBaseTask):
-# def __init__(self, app, cls):
-# form = JobTaskForm(app, "job_release", self, "Release")
-# super(JobReleaseTask, self).__init__(app, cls, form, "Release")
-
-# def do_invoke(self, completion, session, job, reason, scheduler):
-# assert isinstance(scheduler, Scheduler)
-# scheduler.Release(completion, job, reason)
-
-# class JobSetReleaseTask(JobSetBaseTask):
-# def __init__(self, app, cls):
-# super(JobSetReleaseTask, self).__init__(app, cls)
-
-# self.form = JobSetTaskForm(app, "job_set_release", self, "Release")
-# self.item_task = JobReleaseTask(app, cls)
-
-# class JobRemoveTask(JobBaseTask):
-# def __init__(self, app, cls):
-# form = JobTaskForm(app, "job_remove", self, "Remove")
-# super(JobRemoveTask, self).__init__(app, cls, form, "Remove")
-
-# def do_invoke(self, completion, session, job, reason, scheduler):
-# assert isinstance(scheduler, Scheduler)
-# scheduler.Remove(completion, job, reason)
-
-# class JobSetRemoveTask(JobSetBaseTask):
-# def __init__(self, app, cls):
-# super(JobSetRemoveTask, self).__init__(app, cls)
-
-# 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(completion, job, name, str(value))
-
-# def get_title(self, session):
-# return "Set Job Attribute"
Modified: trunk/cumin/python/cumin/grid/pool.py
===================================================================
--- trunk/cumin/python/cumin/grid/pool.py 2011-06-09 14:47:07 UTC (rev 4805)
+++ trunk/cumin/python/cumin/grid/pool.py 2011-06-09 16:31:16 UTC (rev 4806)
@@ -16,6 +16,7 @@
from limit import LimitFrame, LimitSelector
from cumin.grid.quota import QuotaSelector
from cumin.grid.slotvis import SlotOverview
+from cumin.parameters import YoungestAttribute
strings = StringCatalog(__file__)
log = logging.getLogger("cumin.pool")
Modified: trunk/cumin/python/cumin/widgets.py
===================================================================
--- trunk/cumin/python/cumin/widgets.py 2011-06-09 14:47:07 UTC (rev 4805)
+++ trunk/cumin/python/cumin/widgets.py 2011-06-09 16:31:16 UTC (rev 4806)
@@ -1467,11 +1467,12 @@
def set_parameters(self, nsession, session, attribs, name):
self.file_name.set(nsession, name)
for attrib in attribs:
- obj = attrib.get(session)
- cls = obj._class
- self.packages.add(nsession, cls._package._name)
- self.classes.add(nsession, cls._name)
- self.agents.add(nsession, obj._qmf_object_id)
+ if attrib is not None:
+ obj = attrib.get(session)
+ cls = obj._class
+ self.packages.add(nsession, cls._package._name)
+ self.classes.add(nsession, cls._name)
+ self.agents.add(nsession, obj._qmf_object_id)
class IncrementalSearchInput(StringInput, ItemSet):
def __init__(self, app, name, field_param):
12 years, 11 months
r4805 - in trunk: cumin/python/cumin cumin/python/cumin/grid cumin/python/cumin/inventory rosemary/python/rosemary
by tmckay@fedoraproject.org
Author: tmckay
Date: 2011-06-09 14:47:07 +0000 (Thu, 09 Jun 2011)
New Revision: 4805
Removed:
trunk/cumin/python/cumin/grid/collector.py
Modified:
trunk/cumin/python/cumin/grid/dashboard.py
trunk/cumin/python/cumin/grid/limit.py
trunk/cumin/python/cumin/grid/main.py
trunk/cumin/python/cumin/grid/negotiator.py
trunk/cumin/python/cumin/grid/pool.py
trunk/cumin/python/cumin/grid/scheduler.py
trunk/cumin/python/cumin/grid/slot.py
trunk/cumin/python/cumin/grid/slotvis.py
trunk/cumin/python/cumin/grid/submission.py
trunk/cumin/python/cumin/inventory/system.py
trunk/cumin/python/cumin/main.py
trunk/cumin/python/cumin/objectframe.py
trunk/cumin/python/cumin/parameters.py
trunk/cumin/python/cumin/stat.py
trunk/rosemary/python/rosemary/model.py
Log:
Removed filtering on "pool" (derived from com.redhat.grid.Collector) for
Scheduler, Negotiator, Slot, etc. This is to support grid configurations
with hierarchical collectors, where grid objects from agents linked to
subcollectors report a different "pool" value than objects from agents
linked to the top-level collector.
In the process, removed the following dead or now-dead code (classes mostly):
* collector.py (the whole file)
* dashboard.py: DashboardSchedulerStats, DashboardCapacitySlotSummary_, NegotiatorCycles, NegotiatorSlots,
NegotiatorSlotsChart, RosmaryPoolObjectAttribute
* negotiator.py: NegotiatorAttribute
* pool.py: PoolOverview
* slotvis.py: PoolSlotMapPage
* submission.py: PoolSubmitLink
* main.py: TopSubmissionTable.get_collector()
* parameters.py: ObjectAssociateAttribute, CollectorGridAttribute
BZ699413
Deleted: trunk/cumin/python/cumin/grid/collector.py
===================================================================
--- trunk/cumin/python/cumin/grid/collector.py 2011-06-08 18:58:28 UTC (rev 4804)
+++ trunk/cumin/python/cumin/grid/collector.py 2011-06-09 14:47:07 UTC (rev 4805)
@@ -1,66 +0,0 @@
-import logging
-
-from wooly import *
-from wooly.widgets import *
-from wooly.forms import *
-from wooly.resources import *
-from wooly.tables import *
-
-from cumin.objectframe import *
-from cumin.objecttask import *
-from cumin.stat import *
-from cumin.widgets import *
-from cumin.parameters import *
-from cumin.formats import *
-from cumin.util import *
-
-import main
-
-strings = StringCatalog(__file__)
-log = logging.getLogger("cumin.grid.collector")
-
-class CollectorFrame(ObjectFrame):
- def __init__(self, app, name):
- cls = app.model.com_redhat_grid.Collector
-
- super(CollectorFrame, self).__init__(app, name, cls)
-
- self.view.add_tab(CollectorOverview(app, "stats", self.object))
-
- self.start = DaemonStart(app, self, "COLLECTOR")
- self.stop = DaemonStop(app, self, "COLLECTOR")
-
-class CollectorGeneralStatSet(StatSet):
- def __init__(self, app, name, object):
- super(CollectorGeneralStatSet, self).__init__(app, name, object)
-
- self.attrs = ("RunningJobs", "IdleJobs",
- "HostsClaimed", "HostsUnclaimed",
- "HostsOwner", "HostsTotal")
-
-class CollectorOverview(Widget):
- def __init__(self, app, name, collector):
- super(CollectorOverview, self).__init__(app, name)
-
- self.add_child(GeneralStatSet(app, "stats", collector))
-
- chart = self.JobStackedChart(app, "jobs", collector)
- chart.stats = ("RunningJobs", "IdleJobs")
- chart.chart_type = "stacked"
- self.add_child(chart)
-
- chart = self.SlotStackedChart(app, "slots", collector)
- chart.stats = ("HostsClaimed", "HostsUnclaimed", "HostsOwner")
- chart.chart_type = "stacked"
- self.add_child(chart)
-
- def render_title(self, session):
- return "Overview"
-
- class JobStackedChart(StatFlashChart):
- def render_title(self, session):
- return "Job status"
-
- class SlotStackedChart(StatFlashChart):
- def render_title(self, session, *args):
- return "Slot state"
Modified: trunk/cumin/python/cumin/grid/dashboard.py
===================================================================
--- trunk/cumin/python/cumin/grid/dashboard.py 2011-06-08 18:58:28 UTC (rev 4804)
+++ trunk/cumin/python/cumin/grid/dashboard.py 2011-06-09 14:47:07 UTC (rev 4805)
@@ -14,8 +14,8 @@
from cumin.stat import StatSet, PieChartPage, StatFlashChart
from cumin.objectselector import ObjectSelector, MonitorSelfStatColumn, ObjectTableColumn, ObjectTable,\
ObjectLinkColumn, CsvStatsExporter, ExportButton, MonitorSelfAgeColumn
+from cumin.parameters import YoungestAttribute
from cumin.util import rgb_to_string
-from negotiator import NegotiatorAttribute
strings = StringCatalog(__file__)
log = logging.getLogger("cumin.dashboard")
@@ -29,33 +29,26 @@
dashboard = DashboardSummary(app, "d", collector)
self.add_tab(dashboard)
- performance = DashboardPerformance(app, "p", collector)
+ performance = DashboardPerformance(app, "p")
self.add_tab(performance)
- capacity = DashboardCapacity(app, "c", collector)
+ capacity = DashboardCapacity(app, "c")
self.add_tab(capacity)
def render_title(self, session):
return "Overview"
-class DashboardSchedulerStats(Widget):
- def __init__(self, app, name, collector):
- super(DashboardSchedulerStats, self).__init__(app, name)
-
- def render_title(self, session):
- return "Scheuler Stats"
-
class DashboardSummary(Widget):
def __init__(self, app, name, collector):
super(DashboardSummary, self).__init__(app, name)
- job_data = DashboardOverviewJobSummary(app, "job_info", collector)
+ job_data = DashboardOverviewJobSummary(app, "job_info")
self.add_child(job_data)
slot_data = GridSlotsSummary(app, "host_info", collector)
self.add_child(slot_data)
- neg_through = NegotiatorJobThroughput(app, "negotiator_throughput", collector)
+ neg_through = NegotiatorJobThroughput(app, "negotiator_throughput")
self.add_child(neg_through)
cls = app.model.com_redhat_grid.Scheduler
@@ -63,7 +56,7 @@
setattr(cls.MeanTimeToStart, "average", True)
columns = (cls.JobSubmissionRate, cls.JobStartRate, cls.JobCompletionRate, cls.MeanTimeToStart)
- stats = FootnoteDashboardSummaryStats(app, "scheduler_info", collector, cls, columns, "Scheduler.Jobs")
+ stats = FootnoteDashboardSummaryStats(app, "scheduler_info", cls, columns, "Scheduler.Jobs")
stats.title = "Job scheduler info"
self.add_child(stats)
@@ -71,32 +64,34 @@
return "Summary"
class DashboardPerformance(Widget):
- def __init__(self, app, name, collector):
+ def __init__(self, app, name):
super(DashboardPerformance, self).__init__(app, name)
cls = app.model.com_redhat_grid.Collector
- c = MonitorSelfStats(app, "ms_c", collector, cls, "Collector performance", None)
+ coll = YoungestAttribute(app, "coll", cls)
+ c = MonitorSelfStats(app, "ms_c", cls, "Collector performance", None, coll)
self.add_child(c)
cls = app.model.com_redhat_grid.Negotiator
frame = "main.grid.negotiator"
- n = MonitorSelfStats(app, "ms_n", collector, cls, "Negotiator performance", frame)
+ neg = YoungestAttribute(app, "neg", cls)
+ n = MonitorSelfStats(app, "ms_n", cls, "Negotiator performance", frame, neg)
self.add_child(n)
- s = SchedulerPerformance(app, "ms_s", collector)
+ s = SchedulerPerformance(app, "ms_s")
self.add_child(s)
def render_title(self, session):
return "Performance"
class DashboardCapacity(Widget):
- def __init__(self, app, name, collector):
+ def __init__(self, app, name):
super(DashboardCapacity, self).__init__(app, name)
- capacity = DashboardCapacitySlotSummary(app, "slot_capacity", collector)
+ capacity = DashboardCapacitySlotSummary(app, "slot_capacity")
self.add_child(capacity)
- os_data = GridOSBreakdown(app, "os_breakdown", collector)
+ os_data = GridOSBreakdown(app, "os_breakdown")
self.add_child(os_data)
def render_title(self, session):
@@ -140,11 +135,15 @@
self.pie_tmpl = WidgetTemplate(self, "pie_html")
- # don't show this if our object isn't there
def do_render(self, session):
- object = self.object.get(session)
- if object:
- return super(PieStatSet, self).do_render(session)
+ # don't show this if our object isn't there
+ # Some of our children depend on an object, and some
+ # have overloaded do_get_items to read different data,
+ # so if self.object has been set to None skip the check.
+ if self.object:
+ if not self.object.get(session):
+ return
+ return super(PieStatSet, self).do_render(session)
# we generate the style sheet for the legend based on
# the colors defined in the PieChartPage
@@ -349,12 +348,9 @@
return field
class DashboardSumData(ObjectSqlAdapter):
- def __init__(self, app, columns, collector, cls):
+ def __init__(self, app, columns, cls):
super(DashboardSumData, self).__init__(app, cls)
- self.collector = collector
- self.add_value_filter(cls.Pool)
-
for column in columns:
col = "sum(\"%s\")" % column
self.columns.append(col)
@@ -366,9 +362,6 @@
def get_record(self, session):
values = dict()
- obj = self.collector.get(session)
- values[self.cls.Pool.name] = getattr(obj, self.cls.Pool.name)
-
options = DataAdapterOptions()
options.offset = 0
@@ -377,8 +370,8 @@
return records[0]
class DashboardSummaryStats(DefinitionSet):
- def __init__(self, app, name, collector, cls, columns, title):
- super(DashboardSummaryStats, self).__init__(app, name, collector, title)
+ def __init__(self, app, name, cls, columns, title):
+ super(DashboardSummaryStats, self).__init__(app, name, None, title)
self.record = Attribute(app, "totals")
self.add_attribute(self.record)
@@ -386,7 +379,7 @@
self.columns = columns
self.sum_columns = [x.name for x in columns]
self.sum_cls = cls
- self.data = DashboardSumData(app, self.sum_columns, collector, self.sum_cls)
+ self.data = DashboardSumData(app, self.sum_columns, self.sum_cls)
self.title = None
@@ -425,10 +418,10 @@
return record
class FootnoteDashboardSummaryStats(DashboardSummaryStats):
- def __init__(self, app, name, collector, cls, columns, title):
- super(FootnoteDashboardSummaryStats, self).__init__(app, name, collector, cls, columns, title)
+ def __init__(self, app, name, cls, columns, title):
+ super(FootnoteDashboardSummaryStats, self).__init__(app, name, cls, columns, title)
- self.footnote_data = DashboardSumData(app, [cls.WindowedStatWidth.name], collector, cls)
+ self.footnote_data = DashboardSumData(app, [cls.WindowedStatWidth.name], cls)
def render_footnote_value(self, session):
# get the average WindowedStarWidth for all schedulers
@@ -440,8 +433,8 @@
return value
class DashboardPieSummarySet(PieStatSet):
- def __init__(self, app, name, collector, cls, columns, title):
- super(DashboardPieSummarySet, self).__init__(app, name, collector, title)
+ def __init__(self, app, name, cls, columns, title):
+ super(DashboardPieSummarySet, self).__init__(app, name, None, title)
self.record = Attribute(app, "totals")
self.add_attribute(self.record)
@@ -450,7 +443,7 @@
self.columns = columns
self.sum_columns = [x.name for x in columns]
self.sum_cls = cls
- self.data = DashboardSumData(app, self.sum_columns, collector, self.sum_cls)
+ self.data = DashboardSumData(app, self.sum_columns, self.sum_cls)
self.has_total = True
self.color_scheme = PieChartPage.BLUES
@@ -485,12 +478,12 @@
return record
class DashboardOverviewJobSummary(DashboardPieSummarySet):
- def __init__(self, app, name, collector):
+ def __init__(self, app, name):
cls = app.model.com_redhat_grid.Scheduler
columns = [cls.TotalRunningJobs, cls.TotalHeldJobs, cls.TotalIdleJobs,
cls.TotalRemovedJobs, cls.TotalJobAds]
- super(DashboardOverviewJobSummary, self).__init__(app, name, collector, cls, columns, "scheduler.jobs")
+ super(DashboardOverviewJobSummary, self).__init__(app, name, cls, columns, "scheduler.jobs")
self.color_scheme = PieChartPage.GREENS
@@ -499,11 +492,11 @@
class DashboardCapacitySlotSummary(DashboardPieSummarySet):
PERCENT_COLUMN = "% Memory used"
- def __init__(self, app, name, collector):
+ def __init__(self, app, name):
self.cls = app.model.com_redhat_grid.Slot
columns = [self.cls.Disk, self.cls.ImageSize, self.cls.Memory]
- super(DashboardCapacitySlotSummary, self).__init__(app, name, collector, self.cls, columns, "slot.summary")
+ super(DashboardCapacitySlotSummary, self).__init__(app, name, self.cls, columns, "slot.summary")
self.has_pie_chart = False
self.has_total = False
@@ -559,40 +552,6 @@
def get_legend_class(self, session, item):
return "blank"
-class DashboardCapacitySlotSummary_(ObjectSelector):
- def __init__(self, app, name, collector):
- cls = app.model.com_redhat_grid.Slot
- super(DashboardCapacitySlotSummary, self).__init__(app, name, cls)
-
- self.add_filter(collector, cls.Pool)
-
- stat = self.DiskTotalColumn(app, "disk", cls.Disk, "Available disk")
- stat.static_header = True
- self.add_column(stat)
-
- stat = SumSqlColumn(app, "slot_mem_used", cls.ImageSize, "Memory used")
- stat.static_header = True
- self.add_column(stat)
- stat = SumSqlColumn(app, "memtotal", cls.Memory, "Memory total")
- stat.static_header = True
- self.add_column(stat)
- stat = QuotientSqlColumn(app, "percentmem",
- "sum(%s)" % cls.ImageSize.sql_column.identifier,
- "sum(%s)*1024" % cls.Memory.sql_column.identifier)
- stat.static_header = True
- stat.title = "% Memory Used"
- self.add_column(stat)
-
- self.enable_csv_export(collector)
-
- def create_table(self, app, name, cls):
- # avoid the checkboxes
- return MinimalTable(app, name, cls)
-
- class DiskTotalColumn(SumSqlColumn):
- def render_text_align(self, session):
- return "left"
-
class GridSlotsSummary(PieStatSet):
def __init__(self, app, name, collector):
super(GridSlotsSummary, self).__init__(app, name, collector, "collector.hosts")
@@ -625,13 +584,10 @@
return "Aggregate of %s for all slots" % self.attrs[index]
class DashboardOSData(ObjectSqlAdapter):
- def __init__(self, app, collector):
+ def __init__(self, app):
cls = app.model.com_redhat_grid.Slot
super(DashboardOSData, self).__init__(app, cls)
- self.collector = collector
- self.add_value_filter(cls.Pool)
-
self.sum_column = "\"OpSys\""
col = "count(%s)" % self.sum_column
@@ -643,8 +599,6 @@
def get_records(self, session):
values = dict()
- obj = self.collector.get(session)
- values[self.cls.Pool.name] = getattr(obj, self.cls.Pool.name)
options = SqlQueryOptions()
options.sort_column = self.sum_column
@@ -692,13 +646,13 @@
return None
class GridOSBreakdown(PieStatSet):
- def __init__(self, app, name, collector):
- super(GridOSBreakdown, self).__init__(app, name, collector, "slot.os")
+ def __init__(self, app, name):
+ super(GridOSBreakdown, self).__init__(app, name, None, "slot.os")
self.os_records = Attribute(app, "os_breakdown")
self.add_attribute(self.os_records)
- self.os_data = DashboardOSData(app, collector)
+ self.os_data = DashboardOSData(app)
self.color_scheme = PieChartPage.GROUP2
self.has_total = True
@@ -753,8 +707,9 @@
return "legend%s" % rgb_to_string(*(PieChartPage.color_schemes[self.color_scheme][real_index]))
class NegotiatorDefinitionStatSet(PieStatSet):
- def __init__(self, app, name, collector, title):
- self.negotiator = NegotiatorAttribute(app, "neg", collector)
+ def __init__(self, app, name, title):
+ cls = app.model.com_redhat_grid.Negotiator
+ self.negotiator = YoungestAttribute(app, "neg", cls)
super(NegotiatorDefinitionStatSet, self).__init__(app, name, self.negotiator, title)
self.add_attribute(self.negotiator)
@@ -772,12 +727,12 @@
return "legend%s" % rgb_to_string(*(PieChartPage.color_schemes[self.color_scheme][index]))
class NegotiatorJobThroughput(Widget):
- def __init__(self, app, name, collector):
+ def __init__(self, app, name):
super(NegotiatorJobThroughput, self).__init__(app, name)
self.attrs = ["NumJobsConsidered", "Matches", "CandidateSlots", "MatchRate"]
- throughput_stats = JobThroughput(app, "stats", self.attrs, collector)
+ throughput_stats = JobThroughput(app, "stats", self.attrs)
self.add_child(throughput_stats)
chart = self.ThroughputChart(app, "timeseries", throughput_stats.negotiator)
@@ -795,8 +750,8 @@
return "Recent negotiator job throughput"
class JobThroughput(NegotiatorDefinitionStatSet):
- def __init__(self, app, name, attrs, collector):
- super(JobThroughput, self).__init__(app, name, collector, "job.throughput")
+ def __init__(self, app, name, attrs):
+ super(JobThroughput, self).__init__(app, name, "job.throughput")
self.attrs = attrs
@@ -815,65 +770,10 @@
def render_html_title(self, session, item):
return super(JobThroughput, self).render_html_title(session, item[0])
-class NegotiatorCycles(NegotiatorDefinitionStatSet):
- def __init__(self, app, name, collector):
- super(NegotiatorCycles, self).__init__(app, name, collector, "negotiator.cycles")
-
- self.attrs = ["Phase1Duration", "Phase2Duration", "Phase3Duration", "Phase4Duration", "Duration"]
- self.chart_link.stats = self.attrs
-
- self.has_total = True
- self.color_scheme = PieChartPage.RAINBOW
-
- def render_title(self, session):
- return "Negotiator Cycles"
-
-class NegotiatorSlots(NegotiatorDefinitionStatSet):
- def __init__(self, app, name, collector):
- super(NegotiatorSlots, self).__init__(app, name, collector, "negotiator.slots")
-
- self.attrs = ["TrimmedSlots", "CandidateSlots", "TotalSlots"]
- self.chart_link.stats = self.attrs
-
- self.has_total = True
-
- def render_title(self, session):
- return "Negotiator Slots"
-
- def render_width(self, session):
- # disable the pie chart since these stats don't add up to a total
- return 0
-
-class NegotiatorSlotsChart(Widget):
- def __init__(self, app, name, pool):
- super(NegotiatorSlotsChart, self).__init__(app, name)
-
- self.pool = pool
- cls = app.model.com_redhat_grid.Negotiator
- self.object = RosemaryPoolObjectAttribute(app, "obj", pool, cls)
- self.add_attribute(self.object)
-
- slots = self.SlotsChart(app, "slots", self.object)
- slots.stats = ("TotalSlots", "TrimmedSlots", "CandidateSlots")
- self.add_child(slots)
-
- def do_render(self, session):
- object = self.object.get(session)
- if object:
- return super(NegotiatorSlotsChart, self).do_render(session)
-
- class SlotsChart(StatFlashChart):
- def render_title(self, session, *args):
- return "Slots Precessed"
-
-
class MonitorSelfSchedulerTable(ObjectSelector):
- def __init__(self, app, name, pool, cls, frame):
+ def __init__(self, app, name, cls, frame):
super(MonitorSelfSchedulerTable, self).__init__(app, name, cls)
- self.pool = pool
- self.add_filter(self.pool, cls.Pool)
-
col = ObjectLinkColumn(app, "name", cls.Name, cls._id, frame)
self.add_column(col)
@@ -890,20 +790,20 @@
stat = MonitorSelfStatColumn(app, cls.MonitorSelfImageSize.name, cls.MonitorSelfImageSize)
self.add_column(stat)
- self.enable_csv_export(pool)
+ self.enable_csv_export()
def create_table(self, app, name, cls):
# avoid the checkboxes
return MinimalTable(app, name, cls)
class SchedulerPerformance(Widget):
- def __init__(self, app, name, collector):
+ def __init__(self, app, name):
super(SchedulerPerformance, self).__init__(app, name)
cls = app.model.com_redhat_grid.Scheduler
frame = "main.grid.scheduler"
- self.table = MonitorSelfSchedulerTable(app, "current", collector, cls, frame)
+ self.table = MonitorSelfSchedulerTable(app, "current", cls, frame)
self.add_child(self.table)
rates = WidgetSet(app, "rate_widgets")
@@ -914,31 +814,31 @@
cls = app.model.com_redhat_grid.Scheduler
columns = (cls.JobsSubmitted, cls.JobSubmissionRate, cls.JobsSubmittedCum)
- stats = DashboardSummaryStats(app, "submitted", collector, cls, columns, "Jobs.Submitted")
+ stats = DashboardSummaryStats(app, "submitted", cls, columns, "Jobs.Submitted")
stats.title = "Aggregate job submission stats"
rates.add_child(stats)
columns = (cls.JobsStarted, cls.JobStartRate, cls.JobsStartedCum)
- stats = DashboardSummaryStats(app, "started", collector, cls, columns, "Jobs.Started")
+ stats = DashboardSummaryStats(app, "started", cls, columns, "Jobs.Started")
stats.title = "Aggregate job started stats"
rates.add_child(stats)
columns = (cls.JobsCompleted, cls.JobCompletionRate, cls.JobsCompletedCum)
- stats = DashboardSummaryStats(app, "completed", collector, cls, columns, "Jobs.Completed")
+ stats = DashboardSummaryStats(app, "completed", cls, columns, "Jobs.Completed")
stats.title = "Aggregate job completion stats"
rates.add_child(stats)
columns = (cls.JobsExited, cls.JobsExitedCum)
- stats = DashboardSummaryStats(app, "exited", collector, cls, columns, "Jobs.Exited")
+ stats = DashboardSummaryStats(app, "exited", cls, columns, "Jobs.Exited")
stats.title = "Aggregate job exited stats"
others.add_child(stats)
columns = (cls.ShadowExceptions, cls.ShadowExceptionsCum)
- stats = DashboardSummaryStats(app, "exceptions", collector, cls, columns, "Jobs.Exceptions")
+ stats = DashboardSummaryStats(app, "exceptions", cls, columns, "Jobs.Exceptions")
stats.title = "Aggregate job shadow exceptions stats"
others.add_child(stats)
- self.footnote_data = DashboardSumData(app, [cls.WindowedStatWidth.name], collector, cls)
+ self.footnote_data = DashboardSumData(app, [cls.WindowedStatWidth.name], cls)
def render_footnote_value(self, session):
# get the average WindowedStarWidth for all schedulers
@@ -956,21 +856,19 @@
return self.table.render(session)
class MonitorSelfStats(Widget):
- def __init__(self, app, name, pool, cls, title, frame):
+ def __init__(self, app, name, cls, title, frame, object):
super(MonitorSelfStats, self).__init__(app, name)
- self.pool = pool
self.cls = cls
self.frame = frame
self.title = title
-
- self.object = RosemaryPoolObjectAttribute(app, "obj", pool, cls)
+ self.object = object
self.add_attribute(self.object)
- self.chart_link = MonitorSelfCharts(app, "history", pool, cls, self.object)
+ self.chart_link = MonitorSelfCharts(app, "history", self.object)
self.add_child(self.chart_link)
- table = MonitorSelfTable(app, "current", pool, cls, frame, True)
+ table = MonitorSelfTable(app, "current", cls, frame, True)
self.add_child(table)
def do_render(self, session):
@@ -981,12 +879,9 @@
return self.title
class MonitorSelfTable(ObjectSelector):
- def __init__(self, app, name, pool, cls, frame, static):
+ def __init__(self, app, name, cls, frame, static):
super(MonitorSelfTable, self).__init__(app, name, cls)
- self.pool = pool
- self.add_filter(self.pool, cls.Pool)
-
# Do we want the name column to link to the objects page?
# In the case of collector we don't
if frame:
@@ -1012,7 +907,7 @@
stat.static_header = static
self.add_column(stat)
- self.enable_csv_export(pool)
+ self.enable_csv_export()
def create_table(self, app, name, cls):
# avoid the checkboxes
@@ -1022,12 +917,9 @@
return "Current"
class MonitorSelfCharts(Widget):
- def __init__(self, app, name, pool, cls, object):
+ def __init__(self, app, name, object):
super(MonitorSelfCharts, self).__init__(app, name)
- self.pool = pool
- self.cls = cls
-
cpu = self.CPUFlashChart(app, "cpu", object)
cpu.stats = ("MonitorSelfCPUUsage",)
self.add_child(cpu)
@@ -1047,13 +939,3 @@
def render_title(self, session, *args):
return "Socket count"
-class RosemaryPoolObjectAttribute(Attribute):
- def __init__(self, app, name, pool, cls):
- super(RosemaryPoolObjectAttribute, self).__init__(app, name)
-
- self.pool = pool
- self.cls = cls
-
- def get(self, session):
- obj = self.pool.get(session)
- return self.cls.get_object(session.cursor, Pool=obj.Pool)
Modified: trunk/cumin/python/cumin/grid/limit.py
===================================================================
--- trunk/cumin/python/cumin/grid/limit.py 2011-06-08 18:58:28 UTC (rev 4804)
+++ trunk/cumin/python/cumin/grid/limit.py 2011-06-09 14:47:07 UTC (rev 4805)
@@ -20,27 +20,9 @@
LIMIT_FLOAT_VALUE_FOR_UNLIMITED = 1000000.0
class LimitAdapter(ObjectQmfAdapter):
- def __init__(self, app, cls, collector):
- super(LimitAdapter, self).__init__(app, cls)
-
- self.collector = collector
-
def get_negotiator(self, session):
- collector = self.collector.get(session)
cls = self.app.model.com_redhat_grid.Negotiator
-
- # mis-configured pool if there is more than one negotiator
- negs = cls.get_selection(session.cursor, Pool=collector.Pool)
- try:
- youngest = negs[0]
- except IndexError:
- return None
-
- for neg in negs:
- if neg._qmf_update_time > youngest._qmf_update_time:
- youngest = neg
- negotiator = youngest
-
+ negotiator = self.app.model.find_youngest(cls, session.cursor)
return negotiator
def get_count(self, values):
@@ -114,15 +96,15 @@
return limit_max
class LimitSelector(ObjectQmfSelector):
- def __init__(self, app, name, collector):
+ def __init__(self, app, name):
cls = app.model.com_redhat_cumin_grid.Limit
super(LimitSelector, self).__init__(app, name, cls)
self.add_search_filter(self.table.name_col)
- self.table.adapter = LimitAdapter(app, cls, collector)
+ self.table.adapter = LimitAdapter(app, cls)
- self.enable_csv_export(collector)
+ self.enable_csv_export()
def create_table(self, app, name, cls):
return LimitTable(app, name, cls)
Modified: trunk/cumin/python/cumin/grid/main.py
===================================================================
--- trunk/cumin/python/cumin/grid/main.py 2011-06-08 18:58:28 UTC (rev 4804)
+++ trunk/cumin/python/cumin/grid/main.py 2011-06-09 14:47:07 UTC (rev 4805)
@@ -5,7 +5,8 @@
from cumin import *
from cumin.objecttask import *
from cumin.util import *
-from cumin.grid.slotvis import PoolSlotMapPage, PoolSlotFullPage
+from cumin.grid.slot import SlotMapPage
+from cumin.grid.slotvis import PoolSlotFullPage
from model import *
from pool import *
@@ -28,7 +29,7 @@
self.app.main_page.main.grid = self.frame
self.app.main_page.main.add_tab(self.frame)
- self.pool_slots_page = PoolSlotMapPage(self.app, "poolslots.vis")
+ self.pool_slots_page = SlotMapPage(self.app, "poolslots.vis")
self.app.add_page(self.pool_slots_page)
self.pool_slots_fullpage = PoolSlotFullPage \
Modified: trunk/cumin/python/cumin/grid/negotiator.py
===================================================================
--- trunk/cumin/python/cumin/grid/negotiator.py 2011-06-08 18:58:28 UTC (rev 4804)
+++ trunk/cumin/python/cumin/grid/negotiator.py 2011-06-09 14:47:07 UTC (rev 4805)
@@ -22,15 +22,11 @@
super(NegotiatorFrame, self).__init__(app, name, cls)
class NegotiatorSelector(ObjectSelector):
- def __init__(self, app, name, pool):
+ def __init__(self, app, name):
cls = app.model.com_redhat_grid.Negotiator
super(NegotiatorSelector, self).__init__(app, name, cls)
- self.pool = pool
-
- self.add_filter(self.pool, cls.Pool)
-
frame = "main.grid.negotiator"
col = ObjectLinkColumn(app, "name", cls.Name, cls._id, frame)
self.add_column(col)
@@ -49,7 +45,7 @@
#self.start = DaemonSelectionStart(app, self, "NEGOTIATOR")
#self.stop = DaemonSelectionStop(app, self, "NEGOTIATOR")
- self.enable_csv_export(pool)
+ self.enable_csv_export()
def create_table(self, app, name, cls):
# avoid the checkboxes
@@ -446,28 +442,3 @@
negotiator = self.frame.negotiator_attribute.get(osession)
self.form.negotiator.set(session, negotiator)
-class NegotiatorAttribute(Attribute):
- def __init__(self, app, name, collector):
- super(NegotiatorAttribute, self).__init__(app, name)
-
- self.collector = collector
-
- def get(self, session):
- negotiator = super(NegotiatorAttribute, self).get(session)
- if not negotiator:
- cls = self.app.model.com_redhat_grid.Negotiator
-
- pool = self.collector.get(session)
- if pool:
- negotiators = cls.get_selection(session.cursor, Pool=pool.Pool)
- # use the most recently updated one if there are multiple
- if len(negotiators) > 0:
- recent_negotiator = negotiators[0]
- for neg in negotiators:
- if neg._qmf_update_time > \
- recent_negotiator._qmf_update_time:
- recent_negotiator = neg
- self.set(session, recent_negotiator)
- negotiator = recent_negotiator
- return negotiator
-
Modified: trunk/cumin/python/cumin/grid/pool.py
===================================================================
--- trunk/cumin/python/cumin/grid/pool.py 2011-06-08 18:58:28 UTC (rev 4804)
+++ trunk/cumin/python/cumin/grid/pool.py 2011-06-09 14:47:07 UTC (rev 4805)
@@ -5,7 +5,6 @@
from wooly.util import StringCatalog, Writer
from cumin.objectframe import ObjectFrame, ObjectView
-from cumin.parameters import CollectorGridAttribute
from cumin.stat import StatFlashChart, StatSet
from cumin.grid.dashboard import PoolDashboard
@@ -13,10 +12,9 @@
from slot import SlotFrame
from scheduler import SchedulerFrame, SchedulerSelector
from negotiator import NegotiatorFrame, NegotiatorSelector,\
- NegotiatorEditDynamicQuota, NegotiatorAttribute
+ NegotiatorEditDynamicQuota
from limit import LimitFrame, LimitSelector
from cumin.grid.quota import QuotaSelector
-from collector import CollectorGeneralStatSet
from cumin.grid.slotvis import SlotOverview
strings = StringCatalog(__file__)
@@ -48,6 +46,10 @@
def __init__(self, app, name):
cls = app.model.com_redhat_grid.Collector
+ # cls is used by ObjectFrames during the "process" pass
+ # to find self.id and self.object, the handle to an
+ # object in the db and the Rosemary representation of
+ # the object itself.
super(PoolFrame, self).__init__(app, name, cls)
self.icon_href = "resource?name=pool-36.png"
@@ -63,7 +65,7 @@
self.slot = SlotFrame(app, "slot")
self.add_mode(self.slot)
- self.scheduler = SchedulerFrame(app, "scheduler", self.object)
+ self.scheduler = SchedulerFrame(app, "scheduler")
self.add_mode(self.scheduler)
self.negotiator = NegotiatorFrame(app, "negotiator")
@@ -75,26 +77,27 @@
dashboard = PoolDashboard(app, "dashboard", self.object)
self.view.add_tab(dashboard)
- submissions = PoolSubmissionJoinSelector(app, "pool_submissions", self.object)
+ submissions = PoolSubmissionJoinSelector(app, "pool_submissions")
self.view.add_tab(submissions)
- slots = SlotOverview(app, "slots", self.object)
+ slots = SlotOverview(app, "slots")
self.view.add_tab(slots)
- schedulers = SchedulerSelector(app, "schedulers", self.object)
+ schedulers = SchedulerSelector(app, "schedulers")
self.view.add_tab(schedulers)
- negotiators = NegotiatorSelector(app, "negotiators", self.object)
+ negotiators = NegotiatorSelector(app, "negotiators")
self.view.add_tab(negotiators)
- self.negotiator_attribute = NegotiatorAttribute(app, "neg", self.object)
+ cls = app.model.com_redhat_grid.Negotiator
+ self.negotiator_attribute = YoungestAttribute(app, "neg", cls)
self.add_attribute(self.negotiator_attribute)
self.edit_dynamic_quota = NegotiatorEditDynamicQuota(app, self)
self.quotas = QuotaSelector(app, "quotas", self.negotiator_attribute, self)
self.view.add_tab(self.quotas)
- self.limits = LimitSelector(app, "limits", self.object)
+ self.limits = LimitSelector(app, "limits")
self.view.add_tab(self.limits)
self.top_tab = True
@@ -112,110 +115,9 @@
def do_process(self, session):
id = self.id.get(session)
if not id:
- # get all the collectors
- collectors = self.cls.get_selection(session.cursor)
- try:
- youngest = collectors[0]
- except IndexError:
- return
+ collector = self.app.model.find_youngest(self.cls, session.cursor)
+ if collector:
+ self.id.set(session, collector._id)
- for collector in collectors:
- if collector._qmf_update_time > youngest._qmf_update_time:
- youngest = collector
- collector = youngest
- self.id.set(session, collector._id)
-
super(PoolFrame, self).do_process(session)
-class PoolOverview(Widget):
- def __init__(self, app, name, collector):
- super(PoolOverview, self).__init__(app, name)
-
- self.collector = collector
-
- self.grid = CollectorGridAttribute(app, "grid", self.collector)
- self.add_attribute(self.grid)
-
- stats = CollectorGeneralStatSet(app, "collector_stats", self.collector)
- self.add_child(stats)
-
- stats = GridStats(app, "grid_stats", self.grid)
- self.add_child(stats)
-
- 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", self.collector)
- chart.duration.param.default = "3600"
- chart.stats = ("HostsClaimed", "HostsUnclaimed", "HostsOwner")
- chart.chart_type = "stacked"
- self.add_child(chart)
-
- def render_title(self, session):
- return "Overview"
-
- def render_pool_name(self, session):
- collector = self.collector.get(session)
- return collector.Name
-
- class JobStackedChart(StatFlashChart):
- def render_title(self, session):
- return "Job status"
-
- class SlotFlashChart(StatFlashChart):
- def render_title(self, session):
- return "Slot state"
-
-class GridGeneralStatSet(StatSet):
- def __init__(self, app, name, object):
- super(GridGeneralStatSet, self).__init__(app, name, object)
-
- self.attrs = ("NumJobs", "SubmitsInProgress",
- "SubmitsQueued", "SubmitsAllowed",
- "SubmitsWanted", "RunningJobs", "IdleJobs")
-
- def do_render(self, session):
- grid = self.object.get(session)
-
- if grid:
- return super(GridGeneralStatSet, self).do_render(session)
-
-class GridStats(Widget):
- def __init__(self, app, name, grid):
- super(GridStats, self).__init__(app, name)
-
- self.grid = grid
-
- stats = GridGeneralStatSet(app, "stats", self.grid)
- self.add_child(stats)
-
- chart = self.GridJobChart(app, "jobs_chart", self.grid)
- chart.stats = ("NumJobs", "RunningJobs", "IdleJobs")
- self.add_child(chart)
-
- chart = self.GridSubmitChart(app, "submit_chart", self.grid)
- chart.stats = ("SubmitsAllowed", "SubmitsQueued", "SubmitsInProgress")
- self.add_child(chart)
-
- def render_grid_name(self, session):
- grid = self.grid.get(session)
-
- if grid:
- return grid.Name
-
- def do_render(self, session):
- grid = self.grid.get(session)
-
- if grid:
- return super(GridStats, self).do_render(session)
-
- class GridJobChart(StatFlashChart):
- def render_title(self, session):
- return "Grid jobs"
-
- class GridSubmitChart(StatFlashChart):
- def render_title(self, session):
- return "Grid submits"
Modified: trunk/cumin/python/cumin/grid/scheduler.py
===================================================================
--- trunk/cumin/python/cumin/grid/scheduler.py 2011-06-08 18:58:28 UTC (rev 4804)
+++ trunk/cumin/python/cumin/grid/scheduler.py 2011-06-09 14:47:07 UTC (rev 4805)
@@ -16,7 +16,7 @@
log = logging.getLogger("cumin.grid.scheduler")
class SchedulerFrame(ObjectFrame):
- def __init__(self, app, name, pool):
+ def __init__(self, app, name):
cls = app.model.com_redhat_grid.Scheduler
super(SchedulerFrame, self).__init__(app, name, cls)
@@ -30,7 +30,7 @@
overview = SchedulerOverview(app, "overview", self.object)
self.view.add_tab(overview)
- submissions = SchedulerPoolSubmissionSelector(app, "submissions", self.object, pool)
+ submissions = SchedulerPoolSubmissionSelector(app, "submissions", self.object)
self.view.add_tab(submissions)
submitters = SubmitterSelector(app, "submitters", self.object)
@@ -40,12 +40,12 @@
#self.stop = DaemonStop(app, self, "SCHEDD")
class SchedulerPoolSubmissionSelector(PoolSubmissionSelector):
- def __init__(self, app, name, scheduler, pool):
+ def __init__(self, app, name, scheduler):
frame = "main.grid.scheduler.submission"
- super(SchedulerPoolSubmissionSelector, self).__init__(app, name, pool, frame)
+ super(SchedulerPoolSubmissionSelector, self).__init__(app, name, frame)
self.add_reference_filter(scheduler, self.cls.jobserverRef)
- self.enable_csv_export(pool, scheduler)
+ self.enable_csv_export(scheduler)
def create_table(self, app, name, cls):
return self.JoinTable(app, name, cls)
@@ -71,15 +71,11 @@
return values
class SchedulerSelector(ObjectSelector):
- def __init__(self, app, name, pool):
+ def __init__(self, app, name):
cls = app.model.com_redhat_grid.Scheduler
super(SchedulerSelector, self).__init__(app, name, cls)
- self.pool = pool
-
- self.add_filter(self.pool, cls.Pool)
-
frame = "main.grid.scheduler"
col = ObjectLinkColumn(app, "name", cls.Name, cls._id, frame)
self.add_column(col)
@@ -100,7 +96,7 @@
#self.start = DaemonSelectionStart(app, self, "SCHEDD")
#self.stop = DaemonSelectionStop(app, self, "SCHEDD")
- self.enable_csv_export(pool)
+ self.enable_csv_export()
def create_table(self, app, name, cls):
# avoid the checkboxes
Modified: trunk/cumin/python/cumin/grid/slot.py
===================================================================
--- trunk/cumin/python/cumin/grid/slot.py 2011-06-08 18:58:28 UTC (rev 4804)
+++ trunk/cumin/python/cumin/grid/slot.py 2011-06-09 14:47:07 UTC (rev 4805)
@@ -133,7 +133,7 @@
# start creating artificial groupings after the number of real groups
max_top_level_items = 500
- def __init__(self, app, name, param, desc):
+ def __init__(self, app, name, param=None, desc=""):
super(SlotMapPage, self).__init__(app, name)
self.object_param = param
@@ -332,8 +332,17 @@
slot_count = len(records)
root = Element()
+
+ # Not sure these are used. Code was modified
+ # when collector filtering was removed. If values
+ # are needed here they can be synthesized in the case
+ # of a collector
root.name = self.object_description
- root.value = self.object_param.get(session)._id
+ if self.object_param != None:
+ root.value = self.object_param.get(session)._id
+ else:
+ root.value = ""
+
root.slots = slot_count
json = self.json.get(session)
sequence = self.sequence.get(session)
@@ -456,9 +465,6 @@
def render_fullpageable(self, session):
return "fullpageable"
- def get_scheduler_select(self, session):
- raise Exception("Must implement get_scheduler_select")
-
def render_slot_url(self, session):
slot = Identifiable("XXX")
try:
Modified: trunk/cumin/python/cumin/grid/slotvis.py
===================================================================
--- trunk/cumin/python/cumin/grid/slotvis.py 2011-06-08 18:58:28 UTC (rev 4804)
+++ trunk/cumin/python/cumin/grid/slotvis.py 2011-06-09 14:47:07 UTC (rev 4805)
@@ -16,27 +16,21 @@
log = logging.getLogger("cumin.slotvis")
class SlotOverview(RadioModeSet):
- def __init__(self, app, name, pool):
+ def __init__(self, app, name):
super(SlotOverview, self).__init__(app, name)
- self.pool = pool
+ self.add_tab(SlotSelector(app, "slots"))
+ self.add_tab(Visualization(app, "vis"))
- self.add_tab(SlotSelector(app, "slots", pool))
- self.add_tab(Visualization(app, "vis", pool))
-
def render_title(self, session):
return "Slots"
class SlotSelector(ObjectSelector):
- def __init__(self, app, name, pool):
+ def __init__(self, app, name):
cls = app.model.com_redhat_grid.Slot
super(SlotSelector, self).__init__(app, name, cls)
- self.pool = pool
-
- self.add_filter(self.pool, cls.Pool, cls.Pool)
-
frame = "main.grid.slot"
col = ObjectLinkColumn(app, "name", cls.Name, cls._id, frame)
self.add_column(col)
@@ -49,7 +43,7 @@
self.add_column(col)
self.table.set_default_sort_column(col)
- self.enable_csv_export(pool)
+ self.enable_csv_export()
def create_table(self, app, name, cls):
# avoid the checkboxes
@@ -59,99 +53,44 @@
return "Slot table"
class Visualization(Widget):
- def __init__(self, app, name, collector):
+ def __init__(self, app, name):
super(Visualization, self).__init__(app, name)
- self.collector = collector
-
- slot_map = PoolSlotMap(app, "slot_png", self.collector)
+ slot_map = PoolSlotMap(app, "slot_png")
self.add_child(slot_map)
- slot_vis = PoolSlotFlashVis(app, "slot_map", self.collector)
+ slot_vis = PoolSlotFlashVis(app, "slot_map")
self.add_child(slot_vis)
def render_title(self, session):
return "Slot visualization"
class PoolSlotMap(SlotMap):
- def __init__(self, app, name, collector):
- super(PoolSlotMap, self).__init__(app, name)
-
- self.collector = collector
-
- def do_process(self, session):
- super(PoolSlotMap, self).do_process(session)
-
- collector = self.collector.get(session)
-
- self.slots.add_where_expr(session, "\"Pool\" = '%s'", collector.Pool)
-
def render_image_href(self, session):
- collector = self.collector.get(session)
-
page = self.app.grid.pool_slots_page
- sess = Session(page)
+ return Session(page).marshal()
- page.collector.set(sess, collector)
-
- return sess.marshal()
-
- def get_scheduler_select(self, session):
- pass
- #pool = self.pool.get(session)
-
-class PoolSlotMapPage(SlotMapPage):
+class PoolSlotFlashVis(PoolSlotMap):
def __init__(self, app, name):
- cls = app.model.com_redhat_grid.Collector
- self.collector = RosemaryObjectParameter(app, "id", cls)
+ super(PoolSlotFlashVis, self).__init__(app, name)
- super(PoolSlotMapPage, self).__init__(app, name, self.collector, "Pool")
-
- self.add_parameter(self.collector)
-
- def do_process(self, session):
- super(PoolSlotMapPage, self).do_process(session)
-
- collector = self.collector.get(session)
-
- # XXX The conditional is necessary because this page is
- # overloaded to generate little dots, in which case it has no
- # pool
-
- if collector:
- self.slots.add_where_expr(session, "\"Pool\" = '%s'", collector.Pool)
-
-class PoolSlotFlashVis(PoolSlotMap):
- def __init__(self, app, name, object):
- super(PoolSlotFlashVis, self).__init__(app, name, object)
-
self.group_by = self.GroupBySwitch(app, "group_by")
self.add_child(self.group_by)
self.fullpageable = True
def render_slots_href(self, session):
- collector = self.collector.get(session)
-
page = self.app.grid.pool_slots_page
sess = Session(page)
-
- page.collector.set(sess, collector)
page.json.set(sess, "slots")
page.group.set(sess, self.group_by.get(session))
return sess.marshal()
def render_image_href(self, session):
- collector = self.collector.get(session)
-
page = self.app.grid.pool_slots_page
- sess = Session(page)
+ return Session(page).marshal()
- page.collector.set(sess, collector)
-
- return sess.marshal()
-
def render_slot_chart_width(self, session):
return 740
@@ -172,13 +111,8 @@
return self.fullpageable and "fullpageable" or ""
def render_fullpage_href(self, session):
- collector = self.collector.get(session)
-
page = self.app.grid.pool_slots_fullpage
sess = Session(page)
-
- page.collector.set(sess, collector)
-
return sess.marshal()
class GroupBySwitch(StateSwitch):
@@ -197,11 +131,7 @@
def __init__(self, app, name):
super(PoolSlotFullPage, self).__init__(app, name)
- cls = app.model.com_redhat_grid.Collector
- self.collector = RosemaryObjectParameter(app, "id", cls)
- self.add_parameter(self.collector)
-
- self.flash_chart = PoolSlotFlashVis(app, "chart", self.collector)
+ self.flash_chart = PoolSlotFlashVis(app, "chart")
self.flash_chart.fullpageable = False
self.replace_child(self.flash_chart)
Modified: trunk/cumin/python/cumin/grid/submission.py
===================================================================
--- trunk/cumin/python/cumin/grid/submission.py 2011-06-08 18:58:28 UTC (rev 4804)
+++ trunk/cumin/python/cumin/grid/submission.py 2011-06-09 14:47:07 UTC (rev 4805)
@@ -80,13 +80,8 @@
return ObjectTable(app, name, cls)
class PoolSubmissionSelector(SubmissionSelector):
- def __init__(self, app, name, pool, frame="main.grid.submission"):
+ def __init__(self, app, name, frame="main.grid.submission"):
super(PoolSubmissionSelector, self).__init__(app, name)
-
- self.pool = pool
-
- cls = app.model.com_redhat_grid.JobServer
- self.add_filter(self.pool, cls.Pool)
col = self.PoolSubmissionObjectLinkColumn(app, "name", self.cls.Name, self.cls._id, frame)
self.insert_column(0, col)
@@ -96,21 +91,18 @@
col = ObjectTableColumn(app, attr.name, attr)
self.insert_column(1, col)
- link = self.PoolSubmitLink(app, "job_submit", app.grid.job_submit)
+ # Removed PoolSubmitLink, derived from TaskLink, because the
+ # the only method supplied was do_enter which does not exist
+ # in the parent. There are do_enter methods on Tasks,
+ # but not on TaskLinks; this was probably a mistake. 06/7/2001
+ link = TaskLink(app, "job_submit", app.grid.job_submit)
self.links.add_child(link)
- link = self.PoolSubmitLink \
- (app, "dag_job_submit", app.grid.dag_job_submit)
+ link = TaskLink(app, "dag_job_submit", app.grid.dag_job_submit)
self.links.add_child(link)
- link = self.PoolSubmitLink \
- (app, "vm_job_submit", app.grid.vm_job_submit)
+ link = TaskLink(app, "vm_job_submit", app.grid.vm_job_submit)
self.links.add_child(link)
-
- class PoolSubmitLink(TaskLink):
- def do_enter(self, session, obj, form_session):
- pool = self.parent.pool.get(session)
- self.form.pool_name.set(form_session, pool.Pool)
class PoolSubmissionObjectLinkColumn(ObjectLinkColumn):
def render_cell_content(self, session, record):
@@ -118,11 +110,10 @@
if(len(record[self.field.index]) > 50):
retval = record[self.field.index][:50] + "..." #indicate that we truncated the name
return retval
-
class PoolSubmissionJoinSelector(PoolSubmissionSelector):
- def __init__(self, app, name, pool):
- super(PoolSubmissionJoinSelector, self).__init__(app, name, pool)
+ def __init__(self, app, name):
+ super(PoolSubmissionJoinSelector, self).__init__(app, name)
scheduler = app.model.com_redhat_grid.Scheduler
self.SchedulerJoin(app, self.table.adapter.query, self.cls.sql_table,
@@ -132,7 +123,7 @@
col = self.SchedulerColumn(app, "Scheduler", scheduler.Name, scheduler._id, frame)
self.insert_column(2, col)
- self.enable_csv_export(pool)
+ self.enable_csv_export()
class SchedulerColumn(ObjectLinkColumn):
def render_header_content(self, session):
@@ -186,11 +177,9 @@
return "This text will identify the submission"
class JobSchedulerField(ScalarField):
- def __init__(self, app, name, pool_name):
+ def __init__(self, app, name):
super(JobSchedulerField, self).__init__(app, name, None)
- self.pool_name = pool_name
-
self.param = IntegerParameter(app, "param")
self.add_parameter(self.param)
@@ -237,14 +226,7 @@
def do_get_items(self, session):
cls = self.app.model.com_redhat_grid.Scheduler
-
- pool_name = self.parent.pool_name.get(session)
-
- if pool_name:
- schedulers = cls.get_selection(session.cursor, Pool=pool_name)
- else:
- schedulers = cls.get_selection(session.cursor)
-
+ schedulers = cls.get_selection(session.cursor)
return schedulers
def render_item_value(self, session, item):
@@ -388,9 +370,6 @@
cls = app.model.com_redhat_grid.Scheduler
super(JobSubmitForm, self).__init__(app, name, task, cls)
- self.pool_name = Attribute(app, "pool")
- self.add_attribute(self.pool_name)
-
self.description = JobDescriptionField(app, "description")
self.add_field(self.description)
@@ -413,7 +392,7 @@
self.directory.help = "Run the process in this directory"
self.add_field(self.directory)
- self.scheduler = JobSchedulerField(app, "scheduler", self.pool_name)
+ self.scheduler = JobSchedulerField(app, "scheduler")
self.add_extra_field(self.scheduler)
self.universe = self.UniverseField(app, "universe")
@@ -692,9 +671,6 @@
cls = app.model.com_redhat_grid.Scheduler
super(VmJobSubmitForm, self).__init__(app, name, task, cls)
- self.pool_name = Attribute(app, "pool")
- self.add_attribute(self.pool_name)
-
self.description = JobDescriptionField(app, "description")
self.add_field(self.description)
@@ -710,7 +686,7 @@
self.request_disk_MB = self.RequestDiskField(app, "requestdisk")
self.add_extra_field(self.request_disk_MB)
- self.scheduler = JobSchedulerField(app, "scheduler", self.pool_name)
+ self.scheduler = JobSchedulerField(app, "scheduler")
self.add_extra_field(self.scheduler)
self.attrs = JobAttributesField(app, "attrs")
@@ -830,9 +806,6 @@
cls = app.model.com_redhat_grid.Scheduler
super(DagJobSubmitForm, self).__init__(app, name, task, cls)
- self.pool_name = Attribute(app, "pool")
- self.add_attribute(self.pool_name)
-
self.description = JobDescriptionField(app, "description")
self.add_field(self.description)
@@ -842,7 +815,7 @@
self.location.input.size = 50
self.add_field(self.location)
- self.scheduler = JobSchedulerField(app, "scheduler", self.pool_name)
+ self.scheduler = JobSchedulerField(app, "scheduler")
self.add_extra_field(self.scheduler)
self.attrs = JobAttributesField(app, "attrs")
Modified: trunk/cumin/python/cumin/inventory/system.py
===================================================================
--- trunk/cumin/python/cumin/inventory/system.py 2011-06-08 18:58:28 UTC (rev 4804)
+++ trunk/cumin/python/cumin/inventory/system.py 2011-06-09 14:47:07 UTC (rev 4805)
@@ -130,10 +130,6 @@
def render_slot_url(self, session):
return ""
- def get_scheduler_select(self, session):
- system = self.system.get(session)
- return "system='%s'" % system.nodeName
-
class SystemSlotFlashVis(SystemSlotMap):
def render_slots_href(self, session):
system = self.system.get(session)
Modified: trunk/cumin/python/cumin/main.py
===================================================================
--- trunk/cumin/python/cumin/main.py 2011-06-08 18:58:28 UTC (rev 4804)
+++ trunk/cumin/python/cumin/main.py 2011-06-09 14:47:07 UTC (rev 4805)
@@ -554,30 +554,34 @@
for record in data:
# if we can't get the collector, don't render the row
submission_id = record[0]
- collector = self.get_collector(session, submission_id)
- if collector:
+
+ job_server = self.get_job_server(session, submission_id)
+ if job_server:
writer.write(self.row.render(session, record))
-
return writer.to_string()
- def get_collector(self, session, submission_id):
+ def get_job_server(self, session, submission_id):
try:
- cls = self.cls
- submission = cls.get_object_by_id(session.cursor, submission_id)
-
+ submission = self.cls.get_object_by_id(session.cursor, submission_id)
cls = self.app.model.com_redhat_grid.JobServer
- job_server = cls.get_object_by_id(session.cursor, submission._jobserverRef_id)
-
- cls = self.app.model.com_redhat_grid.Collector
- return cls.get_object(session.cursor, Pool=job_server.Pool)
+ return cls.get_object_by_id(session.cursor, submission._jobserverRef_id)
except Exception, e:
log.exception(e)
class NameColumn(ObjectLinkColumn):
def render_cell_href(self, session, record):
submission_id = record[0]
- collector = self.parent.get_collector(session, submission_id)
- if collector:
+
+ cls = self.app.model.com_redhat_grid.Collector
+ collector = self.app.model.find_youngest(cls, session.cursor)
+ job_server = self.parent.get_job_server(session, submission_id)
+
+ # XXX BZ699413
+ # The collector id in the session is referenced by a bunch of
+ # classes, so it still needs to exist, even though it is not
+ # used for filtering. Try to remove references to it in another
+ # pass.
+ if job_server and collector:
branch = session.branch()
self.page.main.grid.id.set(session, collector._id)
self.page.main.grid.submission.id.set(session, submission_id)
Modified: trunk/cumin/python/cumin/objectframe.py
===================================================================
--- trunk/cumin/python/cumin/objectframe.py 2011-06-08 18:58:28 UTC (rev 4804)
+++ trunk/cumin/python/cumin/objectframe.py 2011-06-09 14:47:07 UTC (rev 4805)
@@ -15,9 +15,15 @@
self.cls = cls
+ # This will hold the id of the object that should be assigned
+ # to self.object (it is the _id field from a sql table).
+ # Both the id and the object are typically determined during
+ # the "process" pass before a page is rendered.
self.id = IntegerParameter(app, "id")
self.add_parameter(self.id)
+ # This will be given a value during the "process" pass after
+ # self.id is determined (lookup by id)
self.object = Attribute(app, "object")
self.add_attribute(self.object)
Modified: trunk/cumin/python/cumin/parameters.py
===================================================================
--- trunk/cumin/python/cumin/parameters.py 2011-06-08 18:58:28 UTC (rev 4804)
+++ trunk/cumin/python/cumin/parameters.py 2011-06-09 14:47:07 UTC (rev 4805)
@@ -10,16 +10,6 @@
return login.user
-class ObjectAssociateAttribute(Attribute):
- def __init__(self, app, name, object):
- super(ObjectAssociateAttribute, self).__init__(app, name)
-
- self.object = object
-
- def get(self, session):
- obj = self.object.get(session)
- return self.get_associate(session, obj)
-
class CuminClassParameter(Parameter):
def do_unmarshal(self, string):
return getattr(self.app.model, string, None)
@@ -61,6 +51,19 @@
obj = session.get(self.path)
return obj
+class YoungestAttribute(Attribute):
+ def __init__(self, app, name, cls):
+ super(YoungestAttribute, self).__init__(app, name)
+ self.cls = cls
+
+ def get(self, session):
+ val = super(YoungestAttribute, self).get(session)
+ if not val:
+ val = self.app.model.find_youngest(self.cls, session.cursor)
+ if val:
+ self.set(session, val)
+ return val
+
class BrokerGroupParameter(Parameter):
def do_unmarshal(self, string):
if string == "__none__":
@@ -120,12 +123,6 @@
class PeerParameter(LinkParameter):
pass
-class CollectorGridAttribute(ObjectAssociateAttribute):
- def get_associate(self, session, collector):
- cls = self.app.model.com_redhat_grid.Grid
- grid = cls.get_object(session.cursor, Pool=collector.Pool)
- return grid
-
class QueueParameter(Parameter):
def do_unmarshal(self, string):
return Queue.get(int(string))
Modified: trunk/cumin/python/cumin/stat.py
===================================================================
--- trunk/cumin/python/cumin/stat.py 2011-06-08 18:58:28 UTC (rev 4804)
+++ trunk/cumin/python/cumin/stat.py 2011-06-09 14:47:07 UTC (rev 4805)
@@ -33,7 +33,9 @@
return self.attrs
def do_get_items(self, session):
- object = self.object.get(session)
+ object = None
+ if self.object:
+ object = self.object.get(session)
if not object:
return []
Modified: trunk/rosemary/python/rosemary/model.py
===================================================================
--- trunk/rosemary/python/rosemary/model.py 2011-06-08 18:58:28 UTC (rev 4804)
+++ trunk/rosemary/python/rosemary/model.py 2011-06-09 14:47:07 UTC (rev 4805)
@@ -78,6 +78,21 @@
for pkg in self._packages:
pkg.init_references()
+ @classmethod
+ def find_youngest(cls, rosemary_cls, cursor, **criteria):
+ youngest = None
+ if rosemary_cls._storage != "none":
+ try:
+ objects = rosemary_cls.get_selection(cursor, **criteria)
+ if len(objects) > 0:
+ youngest = objects[0]
+ for obj in objects:
+ if obj._qmf_update_time > youngest._qmf_update_time:
+ youngest = obj
+ except:
+ pass
+ return youngest
+
class RosemaryPackage(object):
def __init__(self, model, name):
self._model = model
12 years, 11 months
r4804 - trunk/cumin/python/cumin
by croberts@fedoraproject.org
Author: croberts
Date: 2011-06-08 18:58:28 +0000 (Wed, 08 Jun 2011)
New Revision: 4804
Modified:
trunk/cumin/python/cumin/model.py
Log:
Catching a rare, but possible exception case and handling it rather than letting an error go to the log file.
Modified: trunk/cumin/python/cumin/model.py
===================================================================
--- trunk/cumin/python/cumin/model.py 2011-06-08 17:11:26 UTC (rev 4803)
+++ trunk/cumin/python/cumin/model.py 2011-06-08 18:58:28 UTC (rev 4804)
@@ -1075,8 +1075,11 @@
self.data[config][group] = raw_configs[group]
def delete(self):
- del self.model.static_group_config_values_by_negotiator[self.negotiator._qmf_agent_id]
- del self.model.dynamic_group_config_values_by_negotiator[self.negotiator._qmf_agent_id]
+ try:
+ del self.model.static_group_config_values_by_negotiator[self.negotiator._qmf_agent_id]
+ del self.model.dynamic_group_config_values_by_negotiator[self.negotiator._qmf_agent_id]
+ except KeyError:
+ pass
super(NegotiatorGroupConfigValuesStore, self).delete()
12 years, 11 months
r4803 - in trunk/cumin/python/cumin: . grid
by croberts@fedoraproject.org
Author: croberts
Date: 2011-06-08 17:11:26 +0000 (Wed, 08 Jun 2011)
New Revision: 4803
Modified:
trunk/cumin/python/cumin/grid/negotiator.py
trunk/cumin/python/cumin/grid/quota.py
trunk/cumin/python/cumin/model.py
Log:
To address BZ: https://bugzilla.redhat.com/show_bug.cgi?id=637963 these changes add an extra column to the quota selector table to show (and separate) the static quotas from the dynamic quotas. In addition, the quota editing form will only show the dynamic quotas that are in the level of the tree currently being edited.
Modified: trunk/cumin/python/cumin/grid/negotiator.py
===================================================================
--- trunk/cumin/python/cumin/grid/negotiator.py 2011-06-06 19:27:19 UTC (rev 4802)
+++ trunk/cumin/python/cumin/grid/negotiator.py 2011-06-08 17:11:26 UTC (rev 4803)
@@ -162,14 +162,17 @@
if len(needed_groups) > 0:
negotiator = self.negotiator.get(session)
- results = self.app.model.get_negotiator_config_values(negotiator, needed_groups, config)
- raw_configs = results.data
+ dynamic_results, static_results = self.app.model.get_negotiator_config_values(negotiator, needed_groups, config)
+ if(config == "GROUP_QUOTA_DYNAMIC"):
+ raw_configs = dynamic_results.data
+ else:
+ raw_configs = static_results.data
try:
for config in raw_configs:
for group in raw_configs[config]:
if raw_configs[config][group].error:
- info[group][config] = raw_configs[config][group].error
+ info[group][config] = "" ##raw_configs[config][group].error
elif raw_configs[config][group].got_data:
info[group][config] = raw_configs[config][group].data['Value']
except Exception, e:
@@ -193,8 +196,11 @@
info = self.get_config_info(session)
total = 0.0
for group in groups:
- value = info[group]["GROUP_QUOTA_DYNAMIC"]
try:
+ value = info[group]["GROUP_QUOTA_DYNAMIC"]
+ except KeyError:
+ info = self.get_config_for_groups(session, "GROUP_QUOTA_DYNAMIC", [group])
+ try:
total = total + float(value)
except:
pass
@@ -270,11 +276,18 @@
def render_groups(self, session):
writer = Writer()
-
+
group_leader = self.group_leader.get(session)
groups = self.group_helper.get_siblings(session, group_leader)
+ info = self.group_helper.get_config_for_groups(session, "GROUP_QUOTA_DYNAMIC", groups)
+ dynamic_groups = []
+ try:
+ dynamic_groups = ["%s" % x for x in groups if info[x]["GROUP_QUOTA_DYNAMIC"] != ""]
+ except:
+ pass
for group in sorted(groups):
- self.field_tmpl.render(writer, session, group)
+ if(group in dynamic_groups):
+ self.field_tmpl.render(writer, session, group)
self.unclaimed_tmpl.render(writer, session, "Unclaimed")
@@ -375,12 +388,12 @@
# don't have to get them again
group_leader = self.group_leader.get(session)
groups = self.group_helper.get_siblings(session, group_leader)
- names = ["name=%s" % x for x in groups]
+ info = self.group_helper.get_config_info(session)
+ names = ["name=%s" % x for x in groups if info[x]["GROUP_QUOTA_DYNAMIC"] != ""]
params.extend(names)
params.append("name=Unclaimed")
- info = self.group_helper.get_config_info(session)
- vals = ["value=%s" % info[x]["GROUP_QUOTA_DYNAMIC"] for x in groups]
+ vals = ["value=%s" % info[x]["GROUP_QUOTA_DYNAMIC"] for x in groups if info[x]["GROUP_QUOTA_DYNAMIC"] != ""]
params.extend(vals)
unclaimed = self.group_helper.get_unclaimed_dyn_quota(session, groups)
params.append("value=%s" % str(unclaimed))
Modified: trunk/cumin/python/cumin/grid/quota.py
===================================================================
--- trunk/cumin/python/cumin/grid/quota.py 2011-06-06 19:27:19 UTC (rev 4802)
+++ trunk/cumin/python/cumin/grid/quota.py 2011-06-08 17:11:26 UTC (rev 4803)
@@ -49,6 +49,13 @@
def fmt_hover(self, group):
return "Edit the %s" % self.field.name
+class StaticQmfGroupColumn(QmfGroupColumn):
+ def __init__(self, app, name, attr, getter, negotiator, task):
+ super(StaticQmfGroupColumn, self).__init__(app, name, attr, getter, negotiator, task)
+
+ def render_header_content(self, session):
+ return "Static quota"
+
class QuotaAdapter(ObjectQmfAdapter):
def get_data(self, values, options):
items = values['items']
@@ -104,6 +111,7 @@
if "." not in sub_name:
items.append(name)
+ self.parent.group_helper.get_config_for_groups(session, "GROUP_QUOTA", items)
self.parent.group_helper.get_config_for_groups(session, "GROUP_QUOTA_DYNAMIC", items)
values['items'] = items
@@ -138,9 +146,13 @@
self.add_column(col)
col = self.GroupColumn(app, "group", cls.Name)
- col.width = "80%"
+ col.width = "70%"
self.add_column(col)
+ task = None
+ col = self.StaticColumn(app, "static", cls.Quota, None, negotiator, task, self.group_helper)
+ self.add_column(col)
+
task = frame.edit_dynamic_quota
col = self.DynamicColumn(app, "dynamic", cls.Quota, None, negotiator, task, self.group_helper)
col.align = "right"
@@ -257,3 +269,36 @@
def render_text_align(self, session):
return "right"
+
+ class StaticColumn(StaticQmfGroupColumn):
+ def __init__(self, app, name, attr, getter, negotiator, task, group_helper):
+ super(QuotaSelector.StaticColumn, self).__init__(app, name, attr, getter, negotiator, task)
+
+ self.group_helper = group_helper
+
+ def render_cell_content(self, session, group):
+ value = self.group_helper.get_config_value(session, group, "GROUP_QUOTA")
+
+ try:
+ fval = float(value)
+ except ValueError:
+ return value
+ except:
+ if isinstance(value, Exception):
+ content = "<span class='QuotaError'>error</span>"
+ val = len(value.args) > 0 and value.args[0] or ""
+ if session.page == self.app.export_page:
+ return val
+ return fmt_link("#", content, "", "", val)
+
+ if session.page == self.app.export_page:
+ return value
+
+
+ content = "%s" % str(round(fval, 2))
+ return content
+
+ def render_text_align(self, session):
+ return "right"
+
+
Modified: trunk/cumin/python/cumin/model.py
===================================================================
--- trunk/cumin/python/cumin/model.py 2011-06-06 19:27:19 UTC (rev 4802)
+++ trunk/cumin/python/cumin/model.py 2011-06-08 17:11:26 UTC (rev 4803)
@@ -29,7 +29,9 @@
self.limits_by_negotiator = dict()
self.job_summaries_by_submission = dict()
self.group_names_by_negotiator = dict()
- self.group_config_values_by_negotiator = dict()
+
+ self.static_group_config_values_by_negotiator = dict()
+ self.dynamic_group_config_values_by_negotiator = dict()
self.lock = Lock()
@@ -96,28 +98,49 @@
def get_negotiator_config_values(self, negotiator, needed_groups, config):
if not negotiator:
- store = NegotiatorGroupConfigValuesStore(self, None)
- store.exception = Exception("Missing Negotiator")
- return store
+ dynamic_store = NegotiatorDynamicGroupConfigValuesStore(self, None)
+ dynamic_store.exception = Exception("Missing Negotiator")
+ static_store = NegotiatorStaticGroupConfigValuesStore(self, None)
+ static_store.exception = Exception("Missing Negotiator")
+ return (dynamic_store, static_store)
self.lock.acquire()
-
+ dynamic_store = None
+ static_store = None
try:
- try:
- store = self.group_config_values_by_negotiator[negotiator._qmf_agent_id]
- store.extend_updates()
- added = 0
- for group in needed_groups:
- added += store.add_group_config(group, config)
- if added > 0:
- store.update_new(None)
- except KeyError:
- store = NegotiatorGroupConfigValuesStore(self, negotiator, needed_groups, config)
- store.start_updates()
+ if config == "GROUP_QUOTA_DYNAMIC":
+ try:
+ dynamic_store = self.dynamic_group_config_values_by_negotiator[negotiator._qmf_agent_id]
+ dynamic_store.extend_updates()
+ added = 0
+ for group in needed_groups:
+ added += dynamic_store.add_group_config(group, config)
+ if added > 0:
+ dynamic_store.update_new(None)
+ except KeyError:
+ dynamic_store = NegotiatorDynamicGroupConfigValuesStore(self, negotiator, needed_groups, config)
+ dynamic_store.start_updates()
+ self.dynamic_group_config_values_by_negotiator[negotiator._qmf_agent_id] = dynamic_store
+ if(negotiator._qmf_agent_id in self.static_group_config_values_by_negotiator.keys()):
+ static_store = self.static_group_config_values_by_negotiator[negotiator._qmf_agent_id]
+ else:
- self.group_config_values_by_negotiator[negotiator._qmf_agent_id] = store
+ try:
+ static_store = self.static_group_config_values_by_negotiator[negotiator._qmf_agent_id]
+ static_store.extend_updates()
+ added = 0
+ for group in needed_groups:
+ added += static_store.add_group_config(group, config)
+ if added > 0:
+ static_store.update_new(None)
+ except KeyError:
+ static_store = NegotiatorStaticGroupConfigValuesStore(self, negotiator, needed_groups, config)
+ static_store.start_updates()
+ self.static_group_config_values_by_negotiator[negotiator._qmf_agent_id] = static_store
+ if(negotiator._qmf_agent_id in self.dynamic_group_config_values_by_negotiator.keys()):
+ dynamic_store = self.dynamic_group_config_values_by_negotiator[negotiator._qmf_agent_id]
- return store
+ return (dynamic_store, static_store)
finally:
self.lock.release()
@@ -128,7 +151,7 @@
self.lock.acquire()
try:
- store = self.group_config_values_by_negotiator[negotiator._qmf_agent_id]
+ store = self.dynamic_group_config_values_by_negotiator[negotiator._qmf_agent_id]
store.update(None)
finally:
self.lock.release()
@@ -1041,8 +1064,8 @@
for config in self.configs:
action = FetchRawConfigSet(self.model.app)
new_configs = list()
- for group in self.configs[config]:
- if group not in self.data[config] or \
+ for group in self.configs.keys():
+ if group not in self.data.keys() or \
self.data[config][group].error or \
not self.data[config][group].data:
new_configs.append(group)
@@ -1052,6 +1075,15 @@
self.data[config][group] = raw_configs[group]
def delete(self):
- del self.model.group_config_values_by_negotiator[self.negotiator._qmf_agent_id]
+ del self.model.static_group_config_values_by_negotiator[self.negotiator._qmf_agent_id]
+ del self.model.dynamic_group_config_values_by_negotiator[self.negotiator._qmf_agent_id]
super(NegotiatorGroupConfigValuesStore, self).delete()
+
+class NegotiatorDynamicGroupConfigValuesStore(NegotiatorGroupConfigValuesStore):
+ def __init__(self, model, negotiator, groups, config):
+ super(NegotiatorDynamicGroupConfigValuesStore, self).__init__(model, negotiator, groups, config)
+
+class NegotiatorStaticGroupConfigValuesStore(NegotiatorGroupConfigValuesStore):
+ def __init__(self, model, negotiator, groups, config):
+ super(NegotiatorStaticGroupConfigValuesStore, self).__init__(model, negotiator, groups, config)
\ No newline at end of file
12 years, 11 months
r4802 - in trunk: cumin/python/cumin wooly/python/wooly
by tmckay@fedoraproject.org
Author: tmckay
Date: 2011-06-06 19:27:19 +0000 (Mon, 06 Jun 2011)
New Revision: 4802
Modified:
trunk/cumin/python/cumin/objectselector.py
trunk/wooly/python/wooly/table.py
Log:
Small tweak to treatment of ascending.default, simplify.
(BZ703860 mods)
Modified: trunk/cumin/python/cumin/objectselector.py
===================================================================
--- trunk/cumin/python/cumin/objectselector.py 2011-06-03 12:07:54 UTC (rev 4801)
+++ trunk/cumin/python/cumin/objectselector.py 2011-06-06 19:27:19 UTC (rev 4802)
@@ -40,12 +40,6 @@
self.export = None
- # If ascending.default is None, ascending.default will be
- # chosen by column data type in init() later on.
- # To force a default value for ascending, set it explicitly
- # in a derived class during __init__
- self.ascending.default = None
-
def init(self):
if not self.adapter:
self.adapter = ObjectSqlAdapter(self.app, self.cls)
Modified: trunk/wooly/python/wooly/table.py
===================================================================
--- trunk/wooly/python/wooly/table.py 2011-06-03 12:07:54 UTC (rev 4801)
+++ trunk/wooly/python/wooly/table.py 2011-06-06 19:27:19 UTC (rev 4802)
@@ -23,12 +23,8 @@
self.sort = SymbolParameter(app, "sort")
self.add_parameter(self.sort)
- # Default for a BooleanParameter is False.
- # ascending.default can be set to None in a
- # derived class if set_default_sort_direction will be used.
self.ascending = BooleanParameter(app, "ascending")
self.add_parameter(self.ascending)
- self._sort_col = None
def get_ascending_by_type(self, the_type):
# Override this method to do something special
@@ -42,16 +38,9 @@
self._sort_col = column
def set_default_sort_direction(self):
- # If the ascending default value has not been
- # explicitly set, choose ascending based on type
- if self.ascending.default == None:
- if self._sort_col:
- self.ascending.default = \
+ if self._sort_col:
+ self.ascending.default = \
self.get_ascending_by_type(self._sort_col.field.type)
- else:
- # If it's still None, and _sort_col was not set,
- # we have to choose something
- self.ascending.default = False
def add_column(self, column):
self.add_child(column)
12 years, 11 months
r4801 - in trunk: cumin/model cumin/python/cumin rosemary/python/rosemary
by croberts@fedoraproject.org
Author: croberts
Date: 2011-06-03 12:07:54 +0000 (Fri, 03 Jun 2011)
New Revision: 4801
Modified:
trunk/cumin/model/rosemary.xml
trunk/cumin/python/cumin/objectselector.py
trunk/rosemary/python/rosemary/util.py
Log:
Taking care of BZ https://bugzilla.redhat.com/show_bug.cgi?id=710283 by removing seconds from the uptime display and adding a key to the label.
Modified: trunk/cumin/model/rosemary.xml
===================================================================
--- trunk/cumin/model/rosemary.xml 2011-06-02 16:24:51 UTC (rev 4800)
+++ trunk/cumin/model/rosemary.xml 2011-06-03 12:07:54 UTC (rev 4801)
@@ -307,7 +307,7 @@
</statistic>
<statistic name="MonitorSelfAge">
- <title>Up-time</title>
+ <title>Up-time (dd:hh:mm)</title>
<formatter>fmt_timestamp_ddhhmmss</formatter>
</statistic>
@@ -444,7 +444,7 @@
</statistic>
<statistic name="MonitorSelfAge">
- <title>Up-time</title>
+ <title>Up-time (dd:hh:mm)</title>
<formatter>fmt_timestamp_ddhhmmss</formatter>
</statistic>
</class>
@@ -537,7 +537,7 @@
</statistic>
<statistic name="MonitorSelfAge">
- <title>Up-time</title>
+ <title>Up-time (dd:hh:mm)</title>
<formatter>fmt_timestamp_ddhhmmss</formatter>
</statistic>
</class>
Modified: trunk/cumin/python/cumin/objectselector.py
===================================================================
--- trunk/cumin/python/cumin/objectselector.py 2011-06-02 16:24:51 UTC (rev 4800)
+++ trunk/cumin/python/cumin/objectselector.py 2011-06-03 12:07:54 UTC (rev 4801)
@@ -571,8 +571,7 @@
days = value / 86400
hours = (value / 3600) - (days * 24)
minutes = (value / 60) - (days * 1440) - (hours * 60)
- seconds = value % 60
- return '%02d:%02d:%02d:%02d' % (days, hours, minutes, seconds)
+ return '%02d:%02d:%02d' % (days, hours, minutes)
class ExportButton(Widget):
def __init__(self, app, name, args, exporter, file_name):
Modified: trunk/rosemary/python/rosemary/util.py
===================================================================
--- trunk/rosemary/python/rosemary/util.py 2011-06-02 16:24:51 UTC (rev 4800)
+++ trunk/rosemary/python/rosemary/util.py 2011-06-03 12:07:54 UTC (rev 4801)
@@ -20,5 +20,4 @@
days = value / 86400
hours = (value / 3600) - (days * 24)
minutes = (value / 60) - (days * 1440) - (hours * 60)
- seconds = value % 60
- return '%02d:%02d:%02d:%02d' % (days, hours, minutes, seconds)
\ No newline at end of file
+ return '%02d:%02d:%02d' % (days, hours, minutes)
\ No newline at end of file
12 years, 11 months
r4800 - trunk/cumin/python/cumin/inventory
by croberts@fedoraproject.org
Author: croberts
Date: 2011-06-02 16:24:51 +0000 (Thu, 02 Jun 2011)
New Revision: 4800
Modified:
trunk/cumin/python/cumin/inventory/system.py
Log:
To address BZ https://bugzilla.redhat.com/show_bug.cgi?id=707584 I have created a new class (from ObjectSlector) that will give us a selector table without the checkboxes that serve no purpose on the inventory page.
Modified: trunk/cumin/python/cumin/inventory/system.py
===================================================================
--- trunk/cumin/python/cumin/inventory/system.py 2011-06-02 14:00:58 UTC (rev 4799)
+++ trunk/cumin/python/cumin/inventory/system.py 2011-06-02 16:24:51 UTC (rev 4800)
@@ -1,6 +1,6 @@
from cumin.grid.slot import SlotMap, SlotMapPage
-from cumin.objectselector import ObjectSelector, ObjectLinkColumn
+from cumin.objectselector import ObjectSelector, ObjectLinkColumn, ObjectTable
from cumin.objectframe import ObjectFrame
from cumin.stat import StatSet, StatFlashChart
from cumin.formats import fmt_bytes
@@ -12,7 +12,14 @@
strings = StringCatalog(__file__)
-class SystemSelector(ObjectSelector):
+class ObjectSelectorTableNoCheckboxes(ObjectSelector):
+ def __init__(self, app, name, cls):
+ super(ObjectSelectorTableNoCheckboxes, self).__init__(app, name, cls)
+
+ def create_table(self, app, name, cls):
+ return ObjectTable(app, name, cls)
+
+class SystemSelector(ObjectSelectorTableNoCheckboxes):
def __init__(self, app, name):
cls = app.model.com_redhat_sesame.Sysimage
12 years, 11 months