r5749 - in trunk: cumin/bin cumin/python/cumin cumin/python/cumin/grid cumin/resources wooly/python/wooly
by croberts@fedoraproject.org
Author: croberts
Date: 2013-03-21 15:01:16 +0000 (Thu, 21 Mar 2013)
New Revision: 5749
Modified:
trunk/cumin/bin/cumin-web
trunk/cumin/python/cumin/config.py
trunk/cumin/python/cumin/grid/dashboard.py
trunk/cumin/python/cumin/grid/dashboard.strings
trunk/cumin/python/cumin/model.py
trunk/cumin/python/cumin/stat.py
trunk/cumin/python/cumin/stat.strings
trunk/cumin/resources/app.css
trunk/cumin/resources/app.js
trunk/wooly/python/wooly/pages.strings
Log:
Changes for BZ 924289. Notably, the "history" radio button is history in favor of "Accounting", but will only show up when plumage data is present. The acccounting group chart is also totally revamped.
Modified: trunk/cumin/bin/cumin-web
===================================================================
--- trunk/cumin/bin/cumin-web 2013-03-19 19:27:17 UTC (rev 5748)
+++ trunk/cumin/bin/cumin-web 2013-03-21 15:01:16 UTC (rev 5749)
@@ -73,6 +73,11 @@
def set_kerberos_configs(cumin, values):
cumin.kerberos_realm = values.kerberos_realm
+def set_plumage_configs(cumin, values):
+ cumin.plumage_host = values.plumage_host
+ cumin.plumage_port = values.plumage_port
+
+
def set_hadoop_configs(cumin, values):
cumin.hadoop_bin_tarball = values.hadoop_bin_tarball
@@ -216,6 +221,7 @@
set_ldap_configs(cumin, values)
set_kerberos_configs(cumin, values)
set_hadoop_configs(cumin, values)
+ set_plumage_configs(cumin, values)
# Not used right now
#cumin.auth_create_ondemand = values.auth_create_ondemand
Modified: trunk/cumin/python/cumin/config.py
===================================================================
--- trunk/cumin/python/cumin/config.py 2013-03-19 19:27:17 UTC (rev 5748)
+++ trunk/cumin/python/cumin/config.py 2013-03-21 15:01:16 UTC (rev 5749)
@@ -161,6 +161,12 @@
param = ConfigParameter(self, "debug", bool)
param.default = False
+
+ param = ConfigParameter(self, "plumage_host", str)
+ param.default = "localhost"
+
+ param = ConfigParameter(self, "plumage_port", int)
+ param.default = 27017
class BrokeredConfigSection(CuminConfigSection):
def __init__(self, config, name, strict_section=False):
Modified: trunk/cumin/python/cumin/grid/dashboard.py
===================================================================
--- trunk/cumin/python/cumin/grid/dashboard.py 2013-03-19 19:27:17 UTC (rev 5748)
+++ trunk/cumin/python/cumin/grid/dashboard.py 2013-03-21 15:01:16 UTC (rev 5749)
@@ -1,4 +1,5 @@
import logging
+import re
from wooly import Widget, Attribute
from wooly.util import StringCatalog, Writer
@@ -7,6 +8,7 @@
from wooly.widgets import RadioModeSet, WidgetSet
from wooly.template import WidgetTemplate
from wooly.forms import StringInput
+from wooly.sql import SqlOperation
from parsley.stringex import rpartition
from rosemary.sqlquery import SqlQueryOptions
@@ -17,7 +19,9 @@
ObjectLinkColumn, CsvStatsExporter, ExportButton, MonitorSelfAgeColumn
from cumin.parameters import YoungestAttribute
from cumin.util import rgb_to_string, xml_escape
+from cumin.model import PlumageChecker
+
strings = StringCatalog(__file__)
log = logging.getLogger("cumin.dashboard")
@@ -36,61 +40,35 @@
capacity = DashboardCapacity(app, "c")
self.add_tab(capacity)
- history = DashboardHistory(app, "h")
- self.add_tab(history)
+ # if plumage data is available, we will have the accounting radio button,
+ # otherwise, it will not appear
+ plumageChecker = PlumageChecker(app)
+ havePlumage = plumageChecker.isPlumageAvailable()
+
+ if havePlumage:
+ accounting = DashboardAccounting(app, "a")
+ self.add_tab(accounting)
def render_title(self, session):
return "Overview"
-class DashboardHistory(Widget):
+class DashboardAccounting(Widget):
def __init__(self, app, name):
- super(DashboardHistory, self).__init__(app, name)
+ super(DashboardAccounting, self).__init__(app, name)
charts = WidgetSet(app, "charts")
self.add_child(charts)
-
- chart = self.PoolEfficiencyChart(app, "eff", app.model.com_redhat_grid_plumage.OSUtil)
- chart.stats = ["efficiency"]
- chart.max_samples = 250
- chart.duration.param.default = "86400"
- charts.add_child(chart)
+
+ chartholder = AccountingChartWidget(app, "accchart")
+ charts.add_child(chartholder)
- chart = self.PoolMemoryChart(app, "fmem", app.model.com_redhat_grid_plumage.OSUtil)
- chart.stats = ["freemem", "usedmem"]
- chart.colors = ["#992600", "#009926"]
- chart.max_samples = 250
- chart.duration.param.default = "86400"
- chart.chart_type = "stacked"
- charts.add_child(chart)
-
- chart = self.PoolCpuChart(app, "fcpu", app.model.com_redhat_grid_plumage.OSUtil)
- chart.stats = [ "freecpu", "usedcpu"]
- chart.colors = ["#992600", "#009926"]
- chart.max_samples = 250
- chart.duration.param.default = "86400"
- chart.chart_type = "stacked"
- charts.add_child(chart)
-
- chart = self.UserUsageChart(app, "useruse", app.model.com_redhat_grid_plumage.Accountant)
- chart.stats = ["resused"]
- chart.max_samples = 250
- filter = ReportingChart.FilterInput(app, "namefilter", app.model.com_redhat_grid_plumage.Accountant, app.model.com_redhat_grid_plumage.Accountant.user.name, "userc", "Filter user")
- chart.filters.append(filter)
- chart.add_child(filter)
- chart.duration.param.default= "86400"
- charts.add_child(chart)
-
def render_title(self, session):
- return "History"
+ return "Accounting"
class PoolMemoryChart(ReportingChart):
def render_title(self, session):
return "Pool memory"
- class PoolCpuChart(ReportingChart):
- def render_title(self, session):
- return "Pool cpus"
-
class PoolEfficiencyChart(ReportingChart):
def render_title(self, session):
return "Pool efficiency"
@@ -101,7 +79,99 @@
class AccountingChart(ReportingChart):
def render_title(self, session):
- return "Usage by parent accounting group"
+ return "Usage by accounting group (cpus)"
+
+class AccountingChartWidget(Widget):
+ def __init__(self, app, name):
+ super(AccountingChartWidget, self).__init__(app, name)
+
+ control = self.AccountingChartControl(app, "actrl")
+ self.add_child(control)
+
+ chart = self.AccountingChart(app, "accuse", app.model.com_redhat_grid_plumage.Accountant)
+ chart.max_samples = 250
+ chart.chart_type = "genusechart"
+ chart.duration.param.default = "86400"
+ chart.leftlegend = False
+ chart.height = 165
+ chart.width = 440
+ self.add_child(chart)
+
+ class AccountingChartControl(Widget):
+ def __init__(self, app, name):
+ super(AccountingChartWidget.AccountingChartControl, self).__init__(app, name)
+ self.app = app
+ self.groupLoader = AccGroupSqlOperation(app)
+
+ def render_chart_div_name(self, session):
+ return self.parent.children_by_name['accuse'].path
+
+ def render_accounting_groups(self, session):
+ display_groups = []
+ trees = {}
+ groups_string = ""
+ groups = self.groupLoader.execute(session).fetchall()
+ groups = [g[0] for g in groups]
+ top_groups = self.groupLoader.getTopLevelGroups(groups)
+ for t_group in top_groups:
+ trees[t_group] = self.groupLoader.build_tree(groups, t_group)
+
+ groups_string = self.processSubTree(trees, "", True)
+
+ return groups_string
+
+ def processSubTree(self, subtree, startString, initialUL=False):
+ if initialUL:
+ subtree_string = "%s <ul id=\"%s\">" % (startString, self.path)
+ else:
+ subtree_string = "%s <ul>" % startString
+ for node in subtree:
+ if len(subtree[node]) > 0:
+ subtree_string += """<li><a href="#">%s</a>""" % node.replace("<", "<").replace(">", ">")
+ subtree_string = self.processSubTree(subtree[node], subtree_string)
+ subtree_string += "</li>"
+ else:
+ subtree_string += """<li><a href="#">%s</a></li>""" % node.replace("<", "<").replace(">", ">")
+ subtree_string += "</ul>"
+ return subtree_string
+
+
+ class AccountingChart(ReportingChart):
+ def render_title(self, session):
+ return "Usage by accounting group (cpus)"
+
+class AccGroupSqlOperation(SqlOperation):
+ def __init__(self, app):
+ super(AccGroupSqlOperation, self).__init__(app)
+
+ def get_connection(self, session):
+ return self.app.database.get_read_connection()
+
+ def getTopLevelGroups(self, groups):
+ topLevelGroups = []
+ for group in groups:
+ split_name = group.split(".",1)
+ if split_name[0] not in topLevelGroups:
+ topLevelGroups.append(split_name[0])
+ return topLevelGroups
+
+ def build_tree(self, nodes, topNode):
+ tree = {}
+ self.build_tree_recursive(tree, topNode, nodes)
+
+ return tree
+
+ def build_tree_recursive(self, tree, parent, nodes):
+ children = []
+ for n in nodes:
+ (nparent, sep, leaf) = n.rpartition(".")
+ if nparent == parent:
+ children.append(n)
+
+ for child in children:
+ tree[child] = {}
+ self.build_tree_recursive(tree[child], child, nodes)
+
class DashboardSummary(Widget):
def __init__(self, app, name, collector):
@@ -110,8 +180,19 @@
job_data = DashboardOverviewJobSummary(app, "job_info")
self.add_child(job_data)
- slot_data = GridSlotsSummary(app, "host_info", collector)
- self.add_child(slot_data)
+ plumageChecker = PlumageChecker(app)
+ havePlumage = plumageChecker.isPlumageAvailable()
+
+ if havePlumage:
+ chart = self.PoolCpuChart(app, "host_info", app.model.com_redhat_grid_plumage.OSUtil)
+ chart.stats = [ "usedcpu", "freecpu"]
+ chart.max_samples = 250
+ chart.duration.param.default = "86400"
+ chart.chart_type = "stacked"
+ self.add_child(chart)
+ else:
+ slot_data = GridSlotsSummary(app, "host_info", collector)
+ self.add_child(slot_data)
neg_through = NegotiatorJobThroughput(app, "negotiator_throughput")
self.add_child(neg_through)
@@ -128,6 +209,10 @@
def render_title(self, session):
return "Summary"
+ class PoolCpuChart(ReportingChart):
+ def render_title(self, session):
+ return "Pool cpus"
+
class DashboardPerformance(Widget):
def __init__(self, app, name):
super(DashboardPerformance, self).__init__(app, name)
Modified: trunk/cumin/python/cumin/grid/dashboard.strings
===================================================================
--- trunk/cumin/python/cumin/grid/dashboard.strings 2013-03-19 19:27:17 UTC (rev 5748)
+++ trunk/cumin/python/cumin/grid/dashboard.strings 2013-03-21 15:01:16 UTC (rev 5749)
@@ -7,6 +7,11 @@
</div>
<div style="clear:both;"></div>
+[DashboardSummary.css]
+div.DashboardSummary div.ReportingStatValueChart {
+ float:left;
+}
+
[MonitorSelfStats.css]
div.MonitorSelfStats div.data {
margin-left: 2em;
@@ -312,20 +317,89 @@
</div>
</div>
-[DashboardHistory.css]
-div.DashboardHistory ul.WidgetSet {
+
+
+[DashboardAccounting.html]
+<div class="{class}">
+ {charts}
+</div>
+<div style="clear:both;"></div>
+
+[DashboardAccounting.css]
+div.DashboardAccounting ul.WidgetSet {
padding: 0;
margin: 0;
list-style: none;
}
-div.DashboardHistory ul.WidgetSet li {
- display: inline;
- float: left;
-}
-[DashboardHistory.html]
+[AccountingChartWidget.html]
<div class="{class}">
- {charts}
+ {actrl}
+ {accuse}
</div>
-<div style="clear:both;"></div>
+
+[AccountingChartWidget.css]
+div.AccountingChartWidget>div {
+ float: left;
+}
+
+
+[AccountingChartControl.html]
+<div id="controlTree" class="{class}"></div>
+<div style="display:none;">
+ {accounting_groups}
+</div>
+
+<script type="text/javascript">
+//<![CDATA[
+var controlTree;
+window.addEvent('domready', function () {
+ controlTree = new MooTreeControl({
+ div: 'controlTree',
+ mode: null,
+ grid: true,
+ onSelect: function(node, state) {
+ //do nothing
+ },
+ onExpand: function(node, state) {
+ var exposed_nodes = [];
+ for(i=0; i < node.nodes.length; i++) {
+ exposed_nodes[i] = node.nodes[i].text;
+ }
+ var chart = cumin.getChart("{chart_div_name}");
+ var chart_url = chart.getParent().getElement("a").getAttribute("href");
+ var nodes = [];
+ getExposedNodes(nodes, this.root);
+ var new_url = get_new_chart_url("{chart_div_name}", chart_url, "groupex", nodes);
+ chart.getParent().getElements('a')[chart_href].set('href', new_url);
+ drawSingleChart(chart, true);
+ }
+ },{
+ text: 'Accounting Groups',
+ open: true
+ });
+ controlTree.adopt('{id}');
+
+});
+
+function getExposedNodes(nodeList, node) {
+ if(node.open == true) {
+ for(var i=0, count=node.nodes.length; i < count; i++) {
+ getExposedNodes(nodeList, node.nodes[i]);
+ }
+ } else {
+ nodeList.push(node.text);
+ }
+}
+//]]>
+</script>
+
+[AccountingChartControl.css]
+div.AccountingChartControl {
+ width : 300px;
+}
+
+[AccGroupSqlOperation.sql]
+select distinct(agroup) from "com.redhat.grid.plumage"."Accountant_samples"
+ order by agroup asc;
Modified: trunk/cumin/python/cumin/model.py
===================================================================
--- trunk/cumin/python/cumin/model.py 2013-03-19 19:27:17 UTC (rev 5748)
+++ trunk/cumin/python/cumin/model.py 2013-03-21 15:01:16 UTC (rev 5749)
@@ -950,3 +950,18 @@
class NegotiatorStaticGroupConfigValuesStore(NegotiatorGroupConfigValuesStore):
def __init__(self, model, negotiator, groups, config):
super(NegotiatorStaticGroupConfigValuesStore, self).__init__(model, negotiator, groups, config)
+
+# Utility class to check for the plumage (data store)
+class PlumageChecker(object):
+ def __init__(self, app):
+ self.app = app
+
+ def isPlumageAvailable(self):
+ plumageAvail = False
+ try:
+ from pymongo import Connection
+ self.connection = Connection(self.app.plumage_host, self.app.plumage_port)
+ plumageAvail = True
+ except:
+ log.info("No plumage data store connection achieved.")
+ return plumageAvail
\ No newline at end of file
Modified: trunk/cumin/python/cumin/stat.py
===================================================================
--- trunk/cumin/python/cumin/stat.py 2013-03-19 19:27:17 UTC (rev 5748)
+++ trunk/cumin/python/cumin/stat.py 2013-03-21 15:01:16 UTC (rev 5749)
@@ -10,6 +10,7 @@
from wooly.pages import HtmlPage
from wooly.parameters import IntegerParameter, ListParameter, StringParameter,\
BooleanParameter
+from wooly.sql import SqlOperation
from cumin.formats import fmt_bytes, fmt_duration_brief
from cumin.model import CuminStatistic, SamplesSqlAdapter
@@ -288,6 +289,10 @@
return self.render_id(session).replace(".", "_")
class ReportingChart(ReportingStatValueChart):
+ def __init__(self, app, name, cls):
+ super(ReportingChart, self).__init__(app, name, cls)
+ self.leftlegend = True #hack to force "leftlegend" class on containing div
+
def get_flash_name(self, session):
return "chart.json"
@@ -317,6 +322,16 @@
def render_id_nodots(self, session):
return self.render_id(session).replace(".", "_")
+ def render_leftlegend(self, session):
+ if self.leftlegend:
+ return "leftlegend"
+ return ""
+
+ def render_legendmargin(self, session):
+ if not self.leftlegend:
+ return "legendmargin"
+ return ""
+
def render_filters(self, session):
filtertext = ""
for f in self.filters:
@@ -814,7 +829,14 @@
return chart.create()
class FlashLineChart(Widget):
+ legendCols = 6
one_day = 24 * 60 * 60
+ stackSeries = False
+ legendLocation = "n"
+ fillAndStroke = True
+ gridPadding = "{top:35, right:20, bottom:20, left:20}"
+ fillAlpha = 0.1
+
def __init__(self, app, name, page):
super(FlashLineChart, self).__init__(app, name)
self.page = page
@@ -912,7 +934,7 @@
msg = "Chart parameters: duration: %s end_secends_ago: %s interval: %s" % (str(duration), str(end_seconds_ago), str(interval))
log.debug(msg)
# get the most recent samples
- samples = self.fetch_samples(adapter, duration, interval,
+ samples = self.fetch_samples(session, adapter, duration, interval,
self.fix_method(method, mode),
mode, delta, stats,
end_seconds_ago=end_seconds_ago)
@@ -929,7 +951,7 @@
if axis_max != max_of_axiis:
msg = "Y-Axis changed. New chart parameters: time_span: %s end_secends_ago: %s interval: %s" % (str(time_span), str(end_seconds_ago), str(interval))
log.debug(msg)
- samples = self.fetch_samples(adapter, time_span, interval,
+ samples = self.fetch_samples(session, adapter, time_span, interval,
self.fix_method(method, mode),
mode, False, stats,
end_seconds_ago=end_seconds_ago)
@@ -943,13 +965,17 @@
# create the chart dict
chart = self.get_chart(session, adapter, stats, samples, time_span, max_value, min_value, append, end_seconds_ago)
#print "**********\n"+chart.create()
- chart.colors = self.colors
chart.graph_div = "%s_chart" % chart.id.replace(".", "_")
- # doing this the ugly way for python 2.4
if self.stackSeries == True:
- chart.stackSeries = 1
+ chart.stackSeries = 1
else:
chart.stackSeries = 0
+ chart.legendLocation = self.legendLocation
+ chart.colors = self.get_colors(samples, session)
+ chart.legendCols = self.legendCols
+ chart.fillAndStroke = self.fillAndStroke
+ chart.gridPadding = self.gridPadding
+ chart.fillAlpha = self.fillAlpha
return chart.create()
def get_y_labels(self, absy, intervals, step):
@@ -1006,7 +1032,7 @@
return y_axis, y_axis_right
- def fetch_samples(self, adapter, dur, interval, method, mode, delta, stats, end_seconds_ago=0):
+ def fetch_samples(self, session, adapter, dur, interval, method, mode, delta, stats, end_seconds_ago=0):
return dict()
def get_max_min(self, session, stats, samples):
@@ -1026,11 +1052,11 @@
# get more samples than needed to allow chart to clip correctly (explains the + 600)
samples[stat] = adapter[stat].samples(stat, dur+600, interval, method, secs2=end_seconds_ago, delta=delta)
- def fetch_samples(self, adapter, dur, interval, method, mode, delta, stats, end_seconds_ago=0):
+ def fetch_samples(self, session, adapter, dur, interval, method, mode, delta, stats, end_seconds_ago=0):
samples = dict()
if mode == "rate":
for stat in stats:
- os = adapter[stat].samples(stat, dur+600, interval, method, secs2=end_seconds_ago, delta=delta)
+ os = adapter.samples(stat, dur+600, interval, method, secs2=end_seconds_ago, delta=delta)
ns = list()
prev = None
@@ -1168,9 +1194,195 @@
new_samples.append((dt, value, dev))
samples[stat] = new_samples
+ def get_colors(self, samples, session):
+ return self.colors
+
class ReportAreaChart(AreaChart):
pass
+class GeneralUseChart(AreaChart):
+ def __init__(self, app, name, page):
+ super(GeneralUseChart, self).__init__(app, name, page)
+ self.stackSeries = True
+ self.legendLocation = "e"
+ self.fillAndStroke = False
+ self.gridPadding = "{top:10, right:20, bottom:20, left:20}" #gets eval'ed in js to form gridPadding object
+ self.legendCols = 2
+ self.fillAlpha = 1
+ self.accGroups = self.AccGroupSqlOperation(app)
+ self.accUse = self.AccGroupUseSqlOperation(app, self)
+
+ self.colors = ("#7eb5d6", "#ad7460", "#397249", "#88382d", "#628b61", "#644436",\
+ "#2a75a9", "#dfc184", "#a84a5c", "#9cb770", "#ec633f", "#2f2f2f",\
+ "#274257", "#8f6048", "#d6a354", "#ccb647", "#f9d654", "#4d4e24")
+
+ def fetch_samples(self, session, adapter, dur, interval, method, mode, delta, stats, end_seconds_ago=0):
+ samples = dict()
+
+ groups_expanded = self.page.group_expand.get(session)
+ #use groups from url, if present, otherwise grab "all" form database
+ groups = groups_expanded if len(groups_expanded) > 0 else self.getTopLevelGroups(self.accGroups.execute(session).fetchall())
+ groups = sorted(groups)
+ for group in groups:
+ group_name = group if isinstance(group, unicode) or isinstance(group, str) else group[0]
+ result = self.accUse.execute(session, group_name, dur, interval).fetchall()
+ if len(result) > 0:
+ samples[group_name] = result
+
+ return samples
+
+ def getTopLevelGroups(self, groups):
+ topLevelGroups = []
+ for group in groups:
+ group = group if isinstance(group, unicode) or isinstance(group, str) else group[0]
+ split_name = group.split(".",1)
+ if split_name[0] not in topLevelGroups:
+ topLevelGroups.append(split_name[0])
+
+ return topLevelGroups
+
+ def get_colors(self, samples, session):
+ ''' takes the chart's default set of colors and maps them
+ to a stat name (group name) to provide persistent colors
+ in the resultant chart even when switching groups around
+ '''
+ colors = []
+ trees = {}
+ color_map = {}
+ all_groups = []
+
+ # figure out what all of our groups are
+ groups = self.accGroups.execute(session).fetchall()
+ groups = [g[0] for g in groups]
+ top_groups = self.getTopLevelGroups(groups)
+ for t_group in top_groups:
+ trees[t_group] = self.build_tree(groups, t_group)
+ self.flatten_tree(trees, all_groups)
+ all_groups = sorted(all_groups)
+
+ # create a designated color for each group
+ for i, group in enumerate(all_groups):
+ color_map[group] = self.colors[i]
+
+ # For all displayed stats, pull the mapped color into the array
+ sample_keys = samples.keys()
+ for stat in sorted(sample_keys):
+ colors.append(color_map[stat])
+ if len(colors) == 0:
+ colors.append("#000000") #default no data color
+
+ return colors
+
+ def flatten_tree(self, dictIn, listOut):
+ for key, value in dictIn.iteritems():
+ if isinstance(value, dict) and len(value) > 0: # If value itself is dictionary
+ if key not in listOut:
+ listOut.append(key)
+ self.flatten_tree(value, listOut)
+ else:
+ listOut.append(key)
+
+ def get_line_title(self, stat):
+ return stat.replace("<", "").replace(">", "")
+
+ def fix_samples(self, samples):
+ # each set of samples needs to be the same length and contain the same x-values
+ x_vals = list()
+ for sample in samples:
+ for point in samples[sample]:
+ if point[0] not in x_vals:
+ x_vals.append(point[0])
+ for sample in samples:
+ for x in x_vals:
+ try:
+ if len(samples[sample]) == 0 or [item[0] for item in samples[sample]].index(x) < 0:
+ samples[sample].append((x, 0, None))
+ except ValueError, e:
+ samples[sample].append((x, 0, None))
+
+
+ def make_chart_lines(self, session, chart, line_type, stats, dot_size, halo_size, line_width, samples, duration, end_secs, mode):
+ chart.elements = list()
+ self.fix_samples(samples)
+
+ for stat in sorted(samples):
+ line = Element()
+ line.type = line_type
+ line.fill_alpha = self.alpha
+
+ line.width = line_width
+ tip_title = stat
+ line.text = mode == "rate" and "%s / sec" % tip_title or self.get_line_title(stat)
+
+ vals = self.get_vals(session, samples, stat, line.text, duration, end_secs)
+ line.values = vals
+ chart.elements.append(line)
+
+ def get_vals(self, session, samples, stat, text, duration, end_secs):
+ tnow = time()
+ vals = list()
+
+ min_dt = tnow - duration - end_secs
+ for dt, value, dev in samples[stat]:
+ if value is not None:
+ vals.append({"dt": secs(dt), "y": value})
+ if secs(dt) < min_dt:
+ break
+
+ #here, we sort by dt to be sure that our graphs are valid
+ vals.sort(key=lambda stat: stat["dt"], reverse=False)
+ return vals
+
+ def build_tree(self, nodes, topNode):
+ tree = {}
+ self.build_tree_recursive(tree, topNode, nodes)
+ return tree
+
+ def build_tree_recursive(self, tree, parent, nodes):
+ children = []
+ for n in nodes:
+ (nparent, sep, leaf) = n.rpartition(".")
+ if nparent == parent:
+ children.append(n)
+
+ for child in children:
+ tree[child] = {}
+ self.build_tree_recursive(tree[child], child, nodes)
+
+ class AccGroupUseSqlOperation(SqlOperation):
+ def __init__(self, app, chart):
+ super(GeneralUseChart.AccGroupUseSqlOperation, self).__init__(app)
+ self.chart = chart
+
+ def get_connection(self, session):
+ return self.app.database.get_read_connection()
+
+ def execute(self, session, group, duration, interval):
+ sql = self.render_sql(session, [group, duration, interval])
+
+ return self.do_execute(session, sql)
+
+ def render_sql(self, session, args):
+ writer = Writer()
+ self.sql_tmpl.render(writer, session, args)
+ return writer.to_string()
+
+ def render_accgroup(self, session, args):
+ return args[0]
+
+ def render_duration(self, session, args):
+ return args[1]
+
+ def render_interval(self, session, args):
+ return args[2]
+
+ class AccGroupSqlOperation(SqlOperation):
+ def __init__(self, app):
+ super(GeneralUseChart.AccGroupSqlOperation, self).__init__(app)
+
+ def get_connection(self, session):
+ return self.app.database.get_read_connection()
+
class StackedAreaChart(AreaChart):
colors = ('#FFABAB', '#ABABFF', '#ABFFAB', '#FFABFF', '#FFFFAB', '#ABFFFF', '#ABABAB')
def __init__(self, app, name, page):
@@ -1179,7 +1391,8 @@
self.points = self.Points(app, "points")
self.add_attribute(self.points)
- self.alpha = 1
+ self.fillAlpha = 0.7
+ self.fillAndStroke = False
self.stackSeries = True
# removed get_vals method since the new way of rendering stacked charts
@@ -1239,12 +1452,12 @@
self.elapsed.default = None
self.add_parameter(self.elapsed)
- # the current y-axis max reported by the .swf
+ # the current y-axis max reported
self.axis_max = IntegerParameter(app, "amax")
self.axis_max.default = 0;
self.add_parameter(self.axis_max)
- # the max y value reported by the .swf
+ # the max y value reported
self.vals_max = IntegerParameter(app, "vmax")
self.vals_max.default = 0;
self.add_parameter(self.vals_max)
@@ -1291,6 +1504,13 @@
self.group_selection = Parameter(app, "groupc")
self.group_selection.default = None
self.add_parameter(self.group_selection)
+
+ groupex_val = Parameter(app, "gp")
+ self.add_parameter(groupex_val)
+
+ self.group_expand = ListParameter(app, "groupex", groupex_val)
+ self.group_expand.default = []
+ self.add_parameter(self.group_expand)
def get_content_type(self, session):
return "text/plain"
@@ -1306,15 +1526,15 @@
chart_obj = AreaChart(self.app, chart_type, self)
elif chart_type == "stacked":
chart_obj = StackedAreaChart(self.app, chart_type, self)
- #chart_obj = StackedChart(self.app, chart_type, self)
elif chart_type == "percent":
chart_obj = PercentAreaChart(self.app, chart_type, self)
elif chart_type == "pie":
chart_obj = FlashPieChart(self.app, chart_type, self)
elif chart_type == "reportarea":
- chart_obj = ReportAreaChart(self.app, chart_type, self)
+ chart_obj = ReportAreaChart(self.app, chart_type, self)
+ elif chart_type == "genusechart":
+ chart_obj = GeneralUseChart(self.app, chart_type, self)
-
return chart_obj
class PercentAreaChart(AreaChart):
Modified: trunk/cumin/python/cumin/stat.strings
===================================================================
--- trunk/cumin/python/cumin/stat.strings 2013-03-19 19:27:17 UTC (rev 5748)
+++ trunk/cumin/python/cumin/stat.strings 2013-03-21 15:01:16 UTC (rev 5749)
@@ -137,6 +137,30 @@
}
[StatValueChart.css]
+/* This gives us a left justified 'n' position for our legend, just have the container div use the leftlegend class */
+div.leftlegend>table.jqplot-table-legend{
+ left:0px !important;
+}
+
+.jqplot-cursor-tooltip {
+ border: 1px solid #cccccc;
+ font-size: 0.75em;
+ white-space: nowrap;
+ background: rgba(255,255,255,0.9);
+ padding: 1px;
+ z-index:10;
+}
+
+.jqplot-highlighter-tooltip, .jqplot-canvasOverlay-tooltip {
+ border: 1px solid #cccccc;
+ font-size: 0.75em;
+ white-space: nowrap;
+ background: rgba(255,255,255,0.9);
+ padding: 1px;
+ z-index:10;
+}
+
+
div.StatValueChart {
font-size: 0.9em;
margin: 0 0 1.5em 0;
@@ -261,7 +285,7 @@
setTimeout(function () {changeDuration(state, a, id, attempt+1);}, 100);
return false;
}
- newurl = get_chart_url(id, $(chart).getParent().getElements('a')[chart_href].get('href'), state);
+ newurl = get_new_chart_url(id, $(chart).getParent().getElements('a')[chart_href].get('href'), 'duration', state);
$(chart).getParent().getElements('a')[chart_href].set('href', newurl);
drawSingleChart(chart, true);
}
@@ -348,7 +372,7 @@
<div>
<!-- don't put this data url inside the holder div, jqplot will kill it on a zoom -->
<a rel="api" type="application/json" href="{href}" style="display:none">Data</a>
- <div id="{id_nodots}_chart" class="jqplotgraph leftlegend" style="height:{height};width:{width};">
+ <div id="{id_nodots}_chart" class="jqplotgraph {leftlegend} {legendmargin}" style="height:{height};width:{width};">
<div class="loading" style="display:none;"><span>Loading...</span></div>
</div>
</div>
@@ -358,6 +382,10 @@
</div>
</div>
+[ReportingChart.css]
+div.ReportingStatValueChart div.legendmargin table.jqplot-table-legend {
+ margin-left: 30px;
+}
[ReportingChart.javascript]
function updateFilter(filter, a, id, param, attempt) {
@@ -407,20 +435,6 @@
return false;
}
-function get_new_chart_url(id, url, param, value) {
- var chart = cumin.getChart(id);
- if (chart == null)
- return false;
-
- var branch = wooly.session.branch(url);
- var now = new Date().getTime();
- branch['elapsed'] = now; // force an entire update
- branch[param] = value;
- url = branch.marshal();
-
- return url;
-}
-
[FilterInput.html]
<!-- <input id="{id}" type="text" name="{name}"></input><input type="button" value="Update filter" {onclick}/> -->
{title}: <select {onchange}>{user_list}</select>
@@ -445,3 +459,16 @@
<div id="{id}_chart">
</div>
</div>
+
+
+[AccGroupSqlOperation.sql]
+select distinct(agroup) from "com.redhat.grid.plumage"."Accountant_samples"
+ order by agroup asc;
+
+[AccGroupUseSqlOperation.sql]
+select max("Accountant_samples"."ts") as interval_end,
+cast(max("Accountant_samples"."resused") as integer) as value,
+stddev("Accountant_samples"."resused") as dev from "com.redhat.grid.plumage"."Accountant_samples"
+where ("Accountant_samples"."user" like '{accgroup}%') and "Accountant_samples"."ts" >= now() - interval '{duration} seconds'
+group by floor(extract(epoch from "Accountant_samples"."ts") / {interval}) order by interval_end desc limit all offset 0;
+
\ No newline at end of file
Modified: trunk/cumin/resources/app.css
===================================================================
--- trunk/cumin/resources/app.css 2013-03-19 19:27:17 UTC (rev 5748)
+++ trunk/cumin/resources/app.css 2013-03-21 15:01:16 UTC (rev 5749)
@@ -824,3 +824,25 @@
{
color: #9FCFFF;
}
+
+.mooTree_node {
+ font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
+ font-size: 12px;
+ white-space: nowrap;
+}
+
+.mooTree_text {
+ padding-top: 3px;
+ height: 15px;
+}
+
+.mooTree_img {
+ float: left;
+ width: 18px;
+ height: 18px;
+ overflow: hidden;
+}
+
+.mooTree_selected {
+
+}
\ No newline at end of file
Modified: trunk/cumin/resources/app.js
===================================================================
--- trunk/cumin/resources/app.js 2013-03-19 19:27:17 UTC (rev 5748)
+++ trunk/cumin/resources/app.js 2013-03-21 15:01:16 UTC (rev 5749)
@@ -590,8 +590,23 @@
dataContainer['x_axis_values'] = dataContainer['x_axis_values']
.append([ json.x_axis.labels.labels[i].text ]);
}
+
+ dataContainer['colors'] = json.colors;
+
dataContainer['stackSeries'] = json.stackSeries == 1 ? true:false;
- dataContainer['colors'] = json.colors;
+ dataContainer['legendLocation'] = json.legendLocation;
+ dataContainer['legendCols'] = json.legendCols;
+ dataContainer['fillAndStroke'] = json.fillAndStroke;
+ eval('var gridPad ='+json.gridPadding);
+ dataContainer['gridPadding'] = gridPad;
+ dataContainer['fillAlpha'] = json.fillAlpha;
+
+ if(dataContainer['labels'].length == 0) {
+ dataContainer['labels'][0] = "No data";
+ dataContainer['y_coordinate_values'][0] = [1,0];
+ dataContainer['colors'] = ["#009926"];
+ }
+
return dataContainer;
}
@@ -622,17 +637,17 @@
text: '',
show: false,
},
- gridPadding: {top:35, right:20, bottom:20, left:20},
+ gridPadding: dataContainer['gridPadding'],
grid: { background: '#FFFFFF' },
legend: {
- show:true,
- location: 'n',
+ show: dataContainer['labels'][0] == "No data" ? false:true,
+ location: dataContainer['legendLocation'],
renderer: $j.jqplot.EnhancedLegendRenderer,
yoffset: 0,
xoffset: 0,
placement: "outside",
rendererOptions:{
- numberColumns:6,
+ numberColumns:dataContainer['legendCols'],
seriesToggle:false,
disableIEFading:true
}
@@ -654,13 +669,13 @@
}
},
series: getSeries(dataContainer),
- stackSeries: dataContainer['stackSeries'],
+ stackSeries: true,
seriesColors: dataContainer['colors'],
seriesDefaults: {
lineWidth:1,
fill:true,
- fillAndStroke:true,
- fillAlpha: 0.1,
+ fillAndStroke:dataContainer['fillAndStroke'],
+ fillAlpha: dataContainer['fillAlpha'],
rendererOptions: {
highlightMouseOver: false,
highlightMouseDown: false,
@@ -730,11 +745,16 @@
allCharts[divName] = $j.jqplot(holder, dataContainer['y_coordinate_values'],chartOptionsObject);
allCharts[divName].target.bind('jqplotResetZoom', cuminChartResetZoom);
allCharts[divName].target.bind('jqplotZoom', cuminChartZoom);
+ allCharts[divName].target.bind('jqplotDataHighlight', cuminChartDataClick);
startChartMonitor(divName);
}
} // end function drawChart
+cuminChartDataClick = function (ev, seriesIndex, pointIndex, data) {
+ //console.log('series: '+seriesIndex+', point: '+pointIndex+', data: '+data);
+}
+
// called on the jqplotZoom event
cuminChartZoom = function(gridpos, datapos, plot, cursor) {
// console.log("cuminZoom");
@@ -755,6 +775,17 @@
// console.log("customPreDraw");
}
+function plot1ClickHandler(ev, gridpos, datapos, neighbor, plot) {
+ if(plot.targetId == "#bargraph") {
+
+ var column = getColumnLocation(plot,gridpos,line1.length);
+
+ //make2nd('doc'+plot.data[0][parseInt(column)][2], plot.data[0][parseInt(column)][0]);
+
+ }
+}
+
+
// used to let us tweak the contents of the tooltip according to our whim, gets called from highlighter plugin showTooltip function
customTooltip = function(str, seriesIndex, pointIndex, plot) {
value = plot.series[seriesIndex].data[pointIndex][1];
@@ -890,3 +921,16 @@
return "anonymous";
}
+function get_new_chart_url(id, url, param, value) {
+ var chart = cumin.getChart(id);
+ if (chart == null)
+ return false;
+
+ var branch = wooly.session.branch(url);
+ var now = new Date().getTime();
+ branch['elapsed'] = now; // force an entire update
+ branch[param] = value;
+ url = branch.marshal();
+
+ return url;
+}
Modified: trunk/wooly/python/wooly/pages.strings
===================================================================
--- trunk/wooly/python/wooly/pages.strings 2013-03-19 19:27:17 UTC (rev 5748)
+++ trunk/wooly/python/wooly/pages.strings 2013-03-21 15:01:16 UTC (rev 5749)
@@ -28,6 +28,7 @@
<script type="text/javascript" src="resource?name=jqplot.highlighter.min.js"></script>
<script type="text/javascript" src="resource?name=jqplot.cursor.js"></script>
<script type="text/javascript" src="resource?name=jqplot.dateAxisRenderer.js"></script>
+ <script type="text/javascript" src="resource?name=mootree.js"></script>
<script type="text/javascript">
$j = jQuery.noConflict();
11 years, 1 month
r5748 - in trunk: mint/python/mint/aviary sage/python/sage/aviary
by tmckay@fedoraproject.org
Author: tmckay
Date: 2013-03-19 19:27:17 +0000 (Tue, 19 Mar 2013)
New Revision: 5748
Modified:
trunk/mint/python/mint/aviary/collector.py
trunk/sage/python/sage/aviary/aviaryoperations.py
Log:
Adding chunking for calls to get_attributes to lessen CPU usage.
Add strip_host flag on BaseCollectorQuery (temporary) that can
be set True to patch against Aviary
Modified: trunk/mint/python/mint/aviary/collector.py
===================================================================
--- trunk/mint/python/mint/aviary/collector.py 2013-03-19 15:04:34 UTC (rev 5747)
+++ trunk/mint/python/mint/aviary/collector.py 2013-03-19 19:27:17 UTC (rev 5748)
@@ -42,7 +42,7 @@
self.ep = ep
self.names = []
-
+ self.strip_host = False
self.objects = dict()
self.recycle_interval = timedelta(seconds=10)
@@ -73,6 +73,25 @@
def get_objects(self, no_summary):
raise Exception("NotImplemented")
+ def get_attributes(self, ids):
+ ads = []
+ final = False
+ stat = False
+ chunk_size = 3
+
+ chunks = [ids[i:i+chunk_size] for i in range(0, len(ids), chunk_size)]
+
+ for chunk in chunks:
+ stat, res = self.ep.app.aviary_ops.get_attributes(self.ep.url,
+ chunk,
+ self.names,
+ self.strip_host)
+ if stat == 0:
+ final = 0
+ ads.extend(res)
+
+ return final, ads
+
def do_the_job(self, foreman):
# If the endpoint has been abandoned, then we should delete the objects
@@ -121,9 +140,7 @@
else:
# get the classad in addition to the ids and summaries
log.debug("Gathering attributes")
- stat, ads = self.ep.app.aviary_ops.get_attributes(self.ep.url,
- ids,
- self.names)
+ stat, ads = self.get_attributes(ids)
if stat == 0:
log.debug("Queueing updates, attribute based")
for ad in ads:
@@ -480,8 +497,10 @@
# Initialize the name index for paging
# We are extending the basic collector endpoint here
self.ep.idx = None
- self.ep.size = 8
+ self.ep.size = 16
+ self.strip_host = False
+
self.names = ["CondorPlatform",
"CondorVersion",
"DaemonStartTime",
Modified: trunk/sage/python/sage/aviary/aviaryoperations.py
===================================================================
--- trunk/sage/python/sage/aviary/aviaryoperations.py 2013-03-19 15:04:34 UTC (rev 5747)
+++ trunk/sage/python/sage/aviary/aviaryoperations.py 2013-03-19 19:27:17 UTC (rev 5748)
@@ -1305,7 +1305,7 @@
def get_slot_id(self, host, page_size, mode=None, offset=None, no_summary=False):
return self._get_obj_by_id(host, page_size, mode, offset, "getSlotID", no_summary)
- def get_attributes(self, host, ids, names=[]):
+ def get_attributes(self, host, ids, names=[], strip_host=False):
if not type(ids) in (list, tuple):
ids = [ids]
@@ -1325,8 +1325,15 @@
host,
"getAttributes")
+
+ def fixname(name):
+ if strip_host and "@" in name:
+ name = name[name.find("@")+1:]
+ return name
+
args = []
for id in ids:
+ id.name = fixname(id.name)
args.append({"id":id,
"names": names})
11 years, 1 month
r5747 - in trunk: cumin/model/admin cumin/model/upgrades rosemary/python/rosemary
by tmckay@fedoraproject.org
Author: tmckay
Date: 2013-03-19 15:04:34 +0000 (Tue, 19 Mar 2013)
New Revision: 5747
Modified:
trunk/cumin/model/admin/cumin.xml
trunk/cumin/model/upgrades/1.3a_to_1.4
trunk/rosemary/python/rosemary/model.py
Log:
Add "sampled" attribute to xml to allow tables which are not sampled.
Remove sample tables for user account data from the schema
Modified: trunk/cumin/model/admin/cumin.xml
===================================================================
--- trunk/cumin/model/admin/cumin.xml 2013-03-19 13:21:11 UTC (rev 5746)
+++ trunk/cumin/model/admin/cumin.xml 2013-03-19 15:04:34 UTC (rev 5747)
@@ -1,19 +1,19 @@
<model>
<package name="com.redhat.cumin">
- <class name="Info">
+ <class name="Info" sampled="n">
<property name="schema_version" type="sstr"/>
</class>
- <class name="User">
+ <class name="User" sampled="n">
<property name="name" type="sstr" index="y"/>
<property name="password" type="sstr"/>
</class>
- <class name="Role">
+ <class name="Role" sampled="n">
<property name="name" type="sstr" index="y"/>
</class>
- <class name="UserRoleMapping">
+ <class name="UserRoleMapping" sampled="n">
<property name="user" references="User" index="y"/>
<property name="role" references="Role" index="y"/>
</class>
Modified: trunk/cumin/model/upgrades/1.3a_to_1.4
===================================================================
--- trunk/cumin/model/upgrades/1.3a_to_1.4 2013-03-19 13:21:11 UTC (rev 5746)
+++ trunk/cumin/model/upgrades/1.3a_to_1.4 2013-03-19 15:04:34 UTC (rev 5747)
@@ -23,6 +23,11 @@
run 'drop schema \"org.apache.qpid.cluster\" cascade'
run 'drop schema \"org.apache.qpid.acl\" cascade'
+run 'drop table if exists \"com.redhat.cumin\".\"Role_samples\" cascade'
+run 'drop table if exists \"com.redhat.cumin\".\"UserRoleMapping_samples\" cascade'
+run 'drop table if exists \"com.redhat.cumin\".\"Info_samples\" cascade'
+run 'drop table if exists \"com.redhat.cumin\".\"User_samples\" cascade'
+
# select 'alter table "' || schemaname || '"."' || tablename || '" drop column "_qmf_create_time" cascade' from pg_tables where
# schemaname like 'com.redhat%' order by "schemaname";
Modified: trunk/rosemary/python/rosemary/model.py
===================================================================
--- trunk/rosemary/python/rosemary/model.py 2013-03-19 13:21:11 UTC (rev 5746)
+++ trunk/rosemary/python/rosemary/model.py 2013-03-19 15:04:34 UTC (rev 5747)
@@ -286,6 +286,7 @@
log.debug("Loading %s", self)
self._storage = elem.get("storage", "database")
+ self._sampled = elem.get("sampled", "y") == "y" and True
assert self._storage in ("database", "none")
@@ -449,19 +450,24 @@
pass
def add_samples_sql(self):
- name = "%s_samples" % self._name
- table = SqlTable(self._package.sql_schema,
- name,
- self._storage)
- self.sql_samples_table = table
+ if self._sampled:
+ name = "%s_samples" % self._name
+ table = SqlTable(self._package.sql_schema,
+ name,
+ self._storage)
+ self.sql_samples_table = table
def add_sql_sample_indices(self):
# Add indices based on the unique column groups
# for the sample table
- for k,v in self._sample_index_col_groups.iteritems():
- SqlIndex(self._package.sql_schema, k, v, self._storage)
+ if self._sampled:
+ for k,v in self._sample_index_col_groups.iteritems():
+ SqlIndex(self._package.sql_schema, k, v, self._storage)
def add_sql_sample_operations(self):
+ if not self._sampled:
+ return
+
self.sql_samples_insert = SqlInsertObjectSamples(
self.sql_samples_table)
@@ -692,11 +698,12 @@
def add_sql_sample_operations(self):
super(Qmf_class, self).add_sql_sample_operations()
+ if self._sampled:
- # Okay, our insert operation needs some extra columns
- # Add them here to the operation created by our parent.
- self.sql_samples_insert.extra_column_names = ("_qmf_agent_id",
- "_qmf_object_id")
+ # Okay, our insert operation needs some extra columns
+ # Add them here to the operation created by our parent.
+ self.sql_samples_insert.extra_column_names = ("_qmf_agent_id",
+ "_qmf_object_id")
def add_sql_constraints(self):
# Add agent and object columns as a unique column set
@@ -707,12 +714,13 @@
def add_samples_sql(self):
super(Qmf_class, self).add_samples_sql()
- a = SqlColumn(self.sql_samples_table, "_qmf_agent_id", sql_text)
- o = SqlColumn(self.sql_samples_table, "_qmf_object_id", sql_text)
- SqlColumn(self.sql_samples_table, "_qmf_update_time", sql_timestamp)
+ if self._sampled:
+ a = SqlColumn(self.sql_samples_table, "_qmf_agent_id", sql_text)
+ o = SqlColumn(self.sql_samples_table, "_qmf_object_id", sql_text)
+ SqlColumn(self.sql_samples_table, "_qmf_update_time", sql_timestamp)
- name = "%s_qmf_id_idx" % self.sql_samples_table._name
- self._sample_index_col_groups[name] = (a, o)
+ name = "%s_qmf_id_idx" % self.sql_samples_table._name
+ self._sample_index_col_groups[name] = (a, o)
def get_object_by_qmf_id(self, cursor, agent_id, object_id):
obj = self._get_rosemary_object(None)
11 years, 1 month
r5746 - trunk/cumin/bin
by tmckay@fedoraproject.org
Author: tmckay
Date: 2013-03-19 13:21:11 +0000 (Tue, 19 Mar 2013)
New Revision: 5746
Modified:
trunk/cumin/bin/cumin-admin
Log:
Remove extra close calls for cursor/connection.
Modified: trunk/cumin/bin/cumin-admin
===================================================================
--- trunk/cumin/bin/cumin-admin 2013-03-19 13:12:17 UTC (rev 5745)
+++ trunk/cumin/bin/cumin-admin 2013-03-19 13:21:11 UTC (rev 5746)
@@ -155,9 +155,11 @@
res = handler(app, conn, cursor, opts, args[1:])
if type(res) is tuple:
conn, cursor = res
- conn.commit()
+ if not conn.closed:
+ conn.commit()
finally:
- cursor.close()
+ if not cursor.closed:
+ cursor.close()
def warn(msg):
print "Warning: %s" % msg
@@ -275,7 +277,6 @@
except SchemaMissing:
error("The schema is missing, run 'cumin-admin create-schema'")
conn.close()
- cursor.close()
target = app.admin.get_target_schema_version()
if curr == target:
11 years, 1 month
r5745 - trunk/cumin/etc
by tmckay@fedoraproject.org
Author: tmckay
Date: 2013-03-19 13:12:17 +0000 (Tue, 19 Mar 2013)
New Revision: 5745
Modified:
trunk/cumin/etc/cumin.conf
Log:
Fix comment and change wallaby params to wallaroo params
Modified: trunk/cumin/etc/cumin.conf
===================================================================
--- trunk/cumin/etc/cumin.conf 2013-03-18 18:06:20 UTC (rev 5744)
+++ trunk/cumin/etc/cumin.conf 2013-03-19 13:12:17 UTC (rev 5745)
@@ -13,8 +13,8 @@
[common]
# database: dbname=cumin
-# wallaby-broker: http://localhost
-# wallaby-refresh: 60
+# wallaroo-host: localhost
+# wallaroo-refresh: 60
# log-level: info
# log-max-mb: 10
# log-max-archives: 1
@@ -180,30 +180,15 @@
## [common]
-## sasl-mech-list:
-## A space separated list that restricts the SASL mechanisms
-## Cumin may use when authenticating to the broker. By default
-## Cumin will use ANONYMOUS authentication if the broker URL does
-## not contain user/password and will use PLAIN or DIGEST-MD5
-## if the broker URL does contain user/password. DIGEST-MD5 is
-## considered more secure than PLAIN by SASL and will be
-## used if is available. This value may be set explicitly
-## to make other choices.
-## Setting the value to 'AVAILABLE' will allow Cumin to use
-## any available mechanism including ANONYMOUS.
+## wallaroo-host: localhost
+## The name of the host where the wallaroo agent is running.
+## The wallaroo agent provides inventory and configuration data
+## that appears on the inventory tab and configuration tab.
-## wallaby-broker: [first item in 'brokers' list]
-## The broker to use for interaction with a Wallaby agent.
-## This is not necessarily the same broker used for grid
-## information. The default value is the
-## first item in the 'brokers' list if not specified. To
-## turn off interaction with Wallaby, set wallaby-broker to
-## the string 'None'.
+## wallaroo-refresh: 60
+## How often in seconds to contact the wallaroo agent
+## to check for new activations
-## wallaby-refresh: 60
-## How often in seconds to contact the Wallaby agent
-## for updated information.
-
## aviary-job-servers: http://localhost:9090
## Specifies the URIs for aviary job servers. The value
## is a comma separated list of URIs. A full URI has the
@@ -223,6 +208,12 @@
## path defaults to /services/query/. Other
## defaults are as noted for aviary-job-servers.
+## aviary-collector-servers: http://localhost:9000
+## Like aviary-job-servers but specifies URIs for aviary
+## collector servers. The port value defaults to 9000 and
+## the path defaults to /services/collector. Other
+## defaults are as noted for aviary-job-servers.
+
## aviary-locator: http://localhost:9000
## Specifies the URI for the aviary locator. This is
## a single value, not a list of URIs. The form of
11 years, 1 month
r5744 - in trunk: cumin/model/upgrades rosemary/python/rosemary
by tmckay@fedoraproject.org
Author: tmckay
Date: 2013-03-18 18:06:20 +0000 (Mon, 18 Mar 2013)
New Revision: 5744
Modified:
trunk/cumin/model/upgrades/1.3a_to_1.4
trunk/rosemary/python/rosemary/model.py
trunk/rosemary/python/rosemary/sqlmodel.py
Log:
Eliminate creation of schema for things with storage = none
Modify the upgrade script for 1.4
Modified: trunk/cumin/model/upgrades/1.3a_to_1.4
===================================================================
--- trunk/cumin/model/upgrades/1.3a_to_1.4 2013-03-18 16:06:30 UTC (rev 5743)
+++ trunk/cumin/model/upgrades/1.3a_to_1.4 2013-03-18 18:06:20 UTC (rev 5744)
@@ -15,70 +15,14 @@
# select 'drop sequence "' || schemaname || '"."' || tablename || '_id_seq"'
# from pg_tables
# where schemaname = 'org.apache.qpid.cluster';
-
-run 'drop sequence \"com.redhat.cumin.messaging\".\"BrokerGroup_id_seq\"'
-run 'drop sequence \"com.redhat.cumin.messaging\".\"BrokerGroupMapping_id_seq\"'
-run 'drop sequence \"org.apache.qpid.broker\".\"ManagementSetupState_id_seq\"'
-run 'drop sequence \"org.apache.qpid.broker\".\"System_id_seq\"'
-run 'drop sequence \"org.apache.qpid.broker\".\"Agent_id_seq\"'
-run 'drop sequence \"org.apache.qpid.broker\".\"Exchange_id_seq\"'
-run 'drop sequence \"org.apache.qpid.broker\".\"Binding_id_seq\"'
-run 'drop sequence \"org.apache.qpid.broker\".\"Subscription_id_seq\"'
-run 'drop sequence \"org.apache.qpid.broker\".\"Link_id_seq\"'
-run 'drop sequence \"org.apache.qpid.broker\".\"Bridge_id_seq\"'
-run 'drop sequence \"org.apache.qpid.broker\".\"Vhost_id_seq\"'
-run 'drop sequence \"org.apache.qpid.broker\".\"Connection_id_seq\"'
-run 'drop sequence \"org.apache.qpid.broker\".\"Session_id_seq\"'
-run 'drop sequence \"org.apache.qpid.broker\".\"Queue_id_seq\"'
-run 'drop sequence \"org.apache.qpid.broker\".\"Broker_id_seq\"'
-run 'drop sequence \"org.apache.qpid.cluster\".\"Cluster_id_seq\"'
-run 'drop sequence \"org.apache.qpid.acl\".\"Acl_id_seq\"'
-run 'drop sequence \"com.redhat.rhm.store\".\"Store_id_seq\"'
-run 'drop sequence \"com.redhat.rhm.store\".\"Journal_id_seq\"'
-# select 'drop table if exists "' || schemaname || '"."' || tablename || '" cascade'
-# from pg_tables
-# where schemaname = 'org.apache.qpid.cluster';
+run 'drop schema \"com.redhat.cumin.messaging\" cascade'
+run 'drop schema \"com.redhat.rhm.store\" cascade'
+run 'drop schema \"com.redhat.cumin.grid\" cascade'
+run 'drop schema \"org.apache.qpid.broker\" cascade'
+run 'drop schema \"org.apache.qpid.cluster\" cascade'
+run 'drop schema \"org.apache.qpid.acl\" cascade'
-run 'drop table if exists \"com.redhat.cumin.messaging\".\"BrokerGroup_samples\" cascade'
-run 'drop table if exists \"com.redhat.cumin.messaging\".\"BrokerGroupMapping_samples\" cascade'
-run 'drop table if exists \"com.redhat.cumin.messaging\".\"BrokerGroup\" cascade'
-run 'drop table if exists \"com.redhat.cumin.messaging\".\"BrokerGroupMapping\" cascade'
-run 'drop table if exists \"org.apache.qpid.broker\".\"System_samples\" cascade'
-run 'drop table if exists \"org.apache.qpid.broker\".\"Broker_samples\" cascade'
-run 'drop table if exists \"org.apache.qpid.broker\".\"Agent_samples\" cascade'
-run 'drop table if exists \"org.apache.qpid.broker\".\"Vhost_samples\" cascade'
-run 'drop table if exists \"org.apache.qpid.broker\".\"Queue_samples\" cascade'
-run 'drop table if exists \"org.apache.qpid.broker\".\"Exchange_samples\" cascade'
-run 'drop table if exists \"org.apache.qpid.broker\".\"Binding_samples\" cascade'
-run 'drop table if exists \"org.apache.qpid.broker\".\"Subscription_samples\" cascade'
-run 'drop table if exists \"org.apache.qpid.broker\".\"Connection_samples\" cascade'
-run 'drop table if exists \"org.apache.qpid.broker\".\"Link_samples\" cascade'
-run 'drop table if exists \"org.apache.qpid.broker\".\"Bridge_samples\" cascade'
-run 'drop table if exists \"org.apache.qpid.broker\".\"Session_samples\" cascade'
-run 'drop table if exists \"org.apache.qpid.broker\".\"ManagementSetupState\" cascade'
-run 'drop table if exists \"org.apache.qpid.broker\".\"ManagementSetupState_samples\" cascade'
-run 'drop table if exists \"org.apache.qpid.broker\".\"System\" cascade'
-run 'drop table if exists \"org.apache.qpid.broker\".\"Agent\" cascade'
-run 'drop table if exists \"org.apache.qpid.broker\".\"Exchange\" cascade'
-run 'drop table if exists \"org.apache.qpid.broker\".\"Binding\" cascade'
-run 'drop table if exists \"org.apache.qpid.broker\".\"Subscription\" cascade'
-run 'drop table if exists \"org.apache.qpid.broker\".\"Link\" cascade'
-run 'drop table if exists \"org.apache.qpid.broker\".\"Bridge\" cascade'
-run 'drop table if exists \"org.apache.qpid.broker\".\"Vhost\" cascade'
-run 'drop table if exists \"org.apache.qpid.broker\".\"Connection\" cascade'
-run 'drop table if exists \"org.apache.qpid.broker\".\"Session\" cascade'
-run 'drop table if exists \"org.apache.qpid.broker\".\"Queue\" cascade'
-run 'drop table if exists \"org.apache.qpid.broker\".\"Broker\" cascade'
-run 'drop table if exists \"org.apache.qpid.cluster\".\"Cluster_samples\" cascade'
-run 'drop table if exists \"org.apache.qpid.cluster\".\"Cluster\" cascade'
-run 'drop table if exists \"org.apache.qpid.acl\".\"Acl_samples\" cascade'
-run 'drop table if exists \"org.apache.qpid.acl\".\"Acl\" cascade'
-run 'drop table if exists \"com.redhat.rhm.store\".\"Store_samples\" cascade'
-run 'drop table if exists \"com.redhat.rhm.store\".\"Journal_samples\" cascade'
-run 'drop table if exists \"com.redhat.rhm.store\".\"Store\" cascade'
-run 'drop table if exists \"com.redhat.rhm.store\".\"Journal\" cascade'
-
# select 'alter table "' || schemaname || '"."' || tablename || '" drop column "_qmf_create_time" cascade' from pg_tables where
# schemaname like 'com.redhat%' order by "schemaname";
@@ -86,10 +30,6 @@
run 'alter table \"com.redhat.cumin\".\"UserRoleMapping\" drop column \"_qmf_create_time\" cascade'
run 'alter table \"com.redhat.cumin\".\"Role\" drop column \"_qmf_create_time\" cascade'
run 'alter table \"com.redhat.cumin\".\"User\" drop column \"_qmf_create_time\" cascade'
-run 'alter table \"com.redhat.cumin.grid\".\"Node\" drop column \"_qmf_create_time\" cascade'
-run 'alter table \"com.redhat.cumin.grid\".\"Limit\" drop column \"_qmf_create_time\" cascade'
-run 'alter table \"com.redhat.cumin.grid\".\"Quota\" drop column \"_qmf_create_time\" cascade'
-run 'alter table \"com.redhat.cumin.grid\".\"JobSummary\" drop column \"_qmf_create_time\" cascade'
run 'alter table \"com.redhat.grid\".\"Master\" drop column \"_qmf_create_time\" cascade'
run 'alter table \"com.redhat.grid\".\"Collector\" drop column \"_qmf_create_time\" cascade'
run 'alter table \"com.redhat.grid\".\"Negotiator\" drop column \"_qmf_create_time\" cascade'
@@ -105,10 +45,6 @@
run 'alter table \"com.redhat.cumin\".\"UserRoleMapping\" drop column \"_qmf_delete_time\" cascade'
run 'alter table \"com.redhat.cumin\".\"Role\" drop column \"_qmf_delete_time\" cascade'
run 'alter table \"com.redhat.cumin\".\"User\" drop column \"_qmf_delete_time\" cascade'
-run 'alter table \"com.redhat.cumin.grid\".\"Node\" drop column \"_qmf_delete_time\" cascade'
-run 'alter table \"com.redhat.cumin.grid\".\"Limit\" drop column \"_qmf_delete_time\" cascade'
-run 'alter table \"com.redhat.cumin.grid\".\"Quota\" drop column \"_qmf_delete_time\" cascade'
-run 'alter table \"com.redhat.cumin.grid\".\"JobSummary\" drop column \"_qmf_delete_time\" cascade'
run 'alter table \"com.redhat.grid\".\"Master\" drop column \"_qmf_delete_time\" cascade'
run 'alter table \"com.redhat.grid\".\"Collector\" drop column \"_qmf_delete_time\" cascade'
run 'alter table \"com.redhat.grid\".\"Negotiator\" drop column \"_qmf_delete_time\" cascade'
@@ -121,4 +57,4 @@
run 'alter table \"com.redhat.sesame\".\"Sysimage\" drop column \"_qmf_delete_time\" cascade'
run 'create index \"Sysimage_nodeName_idx\" on \"com.redhat.sesame\".\"Sysimage\" \(\"nodeName\"\)'
-run 'alter table \"com.redhat.sesame\".\"Sysimage\" drop column uuid cascade'
\ No newline at end of file
+run 'alter table \"com.redhat.sesame\".\"Sysimage\" drop column uuid cascade'
Modified: trunk/rosemary/python/rosemary/model.py
===================================================================
--- trunk/rosemary/python/rosemary/model.py 2013-03-18 16:06:30 UTC (rev 5743)
+++ trunk/rosemary/python/rosemary/model.py 2013-03-18 18:06:20 UTC (rev 5744)
@@ -361,7 +361,7 @@
# meth.extend(child)
for child in elem.findall("index"):
- idx = RosemaryIndex(self, child.get("name"))
+ idx = RosemaryIndex(self, child.get("name"), self._storage)
idx.extend(child)
def check_persistent(self):
@@ -411,9 +411,13 @@
def add_sql_entities(self):
name = "%s_id_seq" % self._name
- self.sql_sequence = SqlSequence(self._package.sql_schema, name)
+ self.sql_sequence = SqlSequence(self._package.sql_schema,
+ name,
+ self._storage)
- self.sql_table = SqlTable(self._package.sql_schema, self._name)
+ self.sql_table = SqlTable(self._package.sql_schema,
+ self._name,
+ self._storage)
id_col = SqlColumn(self.sql_table, "_id", sql_int8)
self.sql_table.key_column = id_col
@@ -446,14 +450,16 @@
def add_samples_sql(self):
name = "%s_samples" % self._name
- table = SqlTable(self._package.sql_schema, name)
+ table = SqlTable(self._package.sql_schema,
+ name,
+ self._storage)
self.sql_samples_table = table
def add_sql_sample_indices(self):
# Add indices based on the unique column groups
# for the sample table
for k,v in self._sample_index_col_groups.iteritems():
- SqlIndex(self._package.sql_schema, k, v)
+ SqlIndex(self._package.sql_schema, k, v, self._storage)
def add_sql_sample_operations(self):
self.sql_samples_insert = SqlInsertObjectSamples(
@@ -1107,9 +1113,10 @@
pass
class RosemaryIndex(object):
- def __init__(self, cls, name):
+ def __init__(self, cls, name, storage):
self.cls = cls
self.name = name
+ self._storage = storage
self.cls._indexes.append(self)
self.cls._indexes_by_name[self.name] = self
@@ -1132,7 +1139,7 @@
name = "%s_%s_idx" % (self.cls._name, self.name)
columns = [x.sql_column for x in self.attributes]
- self.sql_index = SqlIndex(schema, name, columns)
+ self.sql_index = SqlIndex(schema, name, columns, self._storage)
def __repr__(self):
args = (self.__class__.__name__, self.name)
Modified: trunk/rosemary/python/rosemary/sqlmodel.py
===================================================================
--- trunk/rosemary/python/rosemary/sqlmodel.py 2013-03-18 16:06:30 UTC (rev 5743)
+++ trunk/rosemary/python/rosemary/sqlmodel.py 2013-03-18 18:06:20 UTC (rev 5744)
@@ -49,17 +49,39 @@
self._views = list()
self._views_by_name = dict()
+ def add_table(self, table):
+ if table._storage == "database":
+ self._tables.append(table)
+ self._tables_by_name[table._name] = table
+
+ def add_sequence(self, sequence):
+ if sequence._storage == "database":
+ self._sequences.append(sequence)
+ self._sequences_by_name[sequence.name] = sequence
+
+ def add_index(self, index):
+ if index._storage == "database":
+ self._indexes.append(index)
+ self._indexes_by_name[index.name] = index
+
+# def add_view(self, view):
+
def write_create_ddl(self, out):
+ if not (self._tables or self._sequences or self._indexes or self._views):
+ return
+
out.write("create schema %s\n" % self.identifier)
-
for seq in self._sequences:
- seq.write_create_ddl(out)
+ if seq._storage == "database":
+ seq.write_create_ddl(out)
for table in self._tables:
- table.write_create_ddl(out)
+ if table._storage == "database":
+ table.write_create_ddl(out)
for index in self._indexes:
- index.write_create_ddl(out)
+ if index._storage == "database":
+ index.write_create_ddl(out)
for view in self._views:
view.write_create_ddl(out)
@@ -67,36 +89,37 @@
out.write(" ;\n")
def write_drop_ddl(self, out):
- out.write("drop schema %s cascade;\n" % self.identifier)
+ if self._tables or self._sequences or self._indexes or self._views:
+ out.write("drop schema %s cascade;\n" % self.identifier)
def __repr__(self):
args = (self.__class__.__name__, self._name)
return "%s(%s)" % args
class SqlSequence(object):
- def __init__(self, schema, name):
+ def __init__(self, schema, name, storage):
assert isinstance(schema, SqlSchema)
self.schema = schema
self.name = name
+ self._storage = storage
self.identifier = "%s.\"%s\"" % (self.schema.identifier, self.name)
- self.schema._sequences.append(self)
- self.schema._sequences_by_name[self.name] = self
+ self.schema.add_sequence(self)
def write_create_ddl(self, out):
out.write(" create sequence \"%s\"\n" % self.name)
class SqlTable(object):
- def __init__(self, schema, name):
+ def __init__(self, schema, name, storage):
assert isinstance(schema, SqlSchema)
self._schema = schema
self._name = name
+ self._storage = storage
- self._schema._tables.append(self)
- self._schema._tables_by_name[self._name] = self
+ self._schema.add_table(self)
if hasattr(self._schema, self._name):
raise Exception("Collision")
@@ -226,15 +249,15 @@
return " ".join(tokens)
class SqlIndex(object):
- def __init__(self, schema, name, columns):
+ def __init__(self, schema, name, columns, storage):
assert len(set([x.table for x in columns])) == 1
self.schema = schema
self.name = name
self.columns = columns
+ self._storage = storage
- self.schema._indexes.append(self)
- self.schema._indexes_by_name[self.name] = self
+ self.schema.add_index(self)
def write_create_ddl(self, out):
cols = ", ".join(["\"%s\"" % x.name for x in self.columns])
11 years, 1 month
r5743 - in trunk: cumin/resources wooly/resources
by croberts@fedoraproject.org
Author: croberts
Date: 2013-03-18 16:06:30 +0000 (Mon, 18 Mar 2013)
New Revision: 5743
Added:
trunk/cumin/resources/mootree.gif
trunk/wooly/resources/mootree.js
Log:
New files for tree-based accounting groups chart.
Added: trunk/cumin/resources/mootree.gif
===================================================================
(Binary files differ)
Property changes on: trunk/cumin/resources/mootree.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: trunk/wooly/resources/mootree.js
===================================================================
--- trunk/wooly/resources/mootree.js (rev 0)
+++ trunk/wooly/resources/mootree.js 2013-03-18 16:06:30 UTC (rev 5743)
@@ -0,0 +1,692 @@
+/*
+Script: mootree.js
+ My Object Oriented Tree
+ - Developed by Rasmus Schultz, <http://www.mindplay.dk>
+ - Tested with MooTools release 1.2, under Firefox 2, Opera 9 and Internet Explorer 6 and 7.
+
+License:
+ MIT-style license.
+
+Credits:
+ Inspired by:
+ - WebFX xTree, <http://webfx.eae.net/dhtml/xtree/>
+ - Destroydrop dTree, <http://www.destroydrop.com/javascripts/tree/>
+
+Changes:
+
+ rev.12:
+ - load() only worked once on the same node, fixed.
+ - the script would sometimes try to get 'R' from the server, fixed.
+ - the 'load' attribute is now supported in XML files (see example_5.html).
+
+ rev.13:
+ - enable() and disable() added - the adopt() and load() methods use these to improve performance by minimizing the number of visual updates.
+
+ rev.14:
+ - toggle() was using enable() and disable() which actually caused it to do extra work - fixed.
+
+ rev.15:
+ - adopt() now picks up 'href', 'target', 'title' and 'name' attributes of the a-tag, and stores them in the data object.
+ - adopt() now picks up additional constructor arguments from embedded comments, e.g. icons, colors, etc.
+ - documentation now generates properly with NaturalDocs, <http://www.naturaldocs.org/>
+
+ rev.16:
+ - onClick events added to MooTreeControl and MooTreeNode
+ - nodes can now have id's - <MooTreeControl.get> method can be used to find a node with a given id
+
+ rev.17:
+ - changed icon rendering to use innerHTML, making the control faster (and code size slightly smaller).
+
+ rev.18:
+ - migrated to MooTools 1.2 (previous versions no longer supported)
+
+ rev.18.unofficial.1 (croberts)
+ - Added option for no folder display and short-circuited toggle action when a node has no children
+
+*/
+
+var MooTreeIcon = ['I','L','Lminus','Lplus','Rminus','Rplus','T','Tminus','Tplus','_closed','_doc','_open','minus','plus'];
+
+/*
+Class: MooTreeControl
+ This class implements a tree control.
+
+Properties:
+ root - returns the root <MooTreeNode> object.
+ selected - returns the currently selected <MooTreeNode> object, or null if nothing is currently selected.
+
+Events:
+ onExpand - called when a node is expanded or collapsed: function(node, state) - where node is the <MooTreeNode> object that fired the event, and state is a boolean meaning true:expanded or false:collapsed.
+ onSelect - called when a node is selected or deselected: function(node, state) - where node is the <MooTreeNode> object that fired the event, and state is a boolean meaning true:selected or false:deselected.
+ onClick - called when a node is clicked: function(node) - where node is the <MooTreeNode> object that fired the event.
+
+Parameters:
+ The constructor takes two object parameters: config and options.
+ The first, config, contains global settings for the tree control - you can use the configuration options listed below.
+ The second, options, should contain options for the <MooTreeNode> constructor - please refer to the options listed in the <MooTreeNode> documentation.
+
+Config:
+ div - a string representing the div Element inside which to build the tree control.
+ mode - optional string, defaults to 'files' - specifies default icon behavior. In 'files' mode, empty nodes have a document icon - whereas, in 'folders' mode, all nodes are displayed as folders (a'la explorer).
+ grid - boolean, defaults to false. If set to true, a grid is drawn to outline the structure of the tree.
+
+ theme - string, optional, defaults to 'mootree.gif' - specifies the 'theme' GIF to use.
+
+ loader - optional, an options object for the <MooTreeNode> constructor - defaults to {icon:'mootree_loader.gif', text:'Loading...', color:'a0a0a0'}
+
+ onExpand - optional function (see Events above)
+ onSelect - optional function (see Events above)
+
+*/
+
+var MooTreeControl = new Class({
+
+ initialize: function(config, options) {
+
+ options.control = this; // make sure our new MooTreeNode knows who it's owner control is
+ options.div = config.div; // tells the root node which div to insert itself into
+ this.root = new MooTreeNode(options); // create the root node of this tree control
+
+ this.index = new Object(); // used by the get() method
+
+ this.enabled = true; // enable visual updates of the control
+
+ this.theme = config.theme || 'resource?name=mootree.gif';
+
+ this.loader = config.loader || {icon:'resource?name=mootree_loader.gif', text:'Loading...', color:'#a0a0a0'};
+
+ this.selected = null; // set the currently selected node to nothing
+ this.mode = config.mode; // mode can be "folders" or "files", and affects the default icons, setting this to null will result in no icons being used
+ this.grid = config.grid; // grid can be turned on (true) or off (false)
+
+ this.onExpand = config.onExpand || new Function(); // called when any node in the tree is expanded/collapsed
+ this.onSelect = config.onSelect || new Function(); // called when any node in the tree is selected/deselected
+ this.onClick = config.onClick || new Function(); // called when any node in the tree is clicked
+
+ this.root.update(true);
+
+ },
+
+ /*
+ Property: insert
+ Creates a new node under the root node of this tree.
+
+ Parameters:
+ options - an object containing the same options available to the <MooTreeNode> constructor.
+
+ Returns:
+ A new <MooTreeNode> instance.
+ */
+
+ insert: function(options) {
+ options.control = this;
+ return this.root.insert(options);
+ },
+
+ /*
+ Property: select
+ Sets the currently selected node.
+ This is called by <MooTreeNode> when a node is selected (e.g. by clicking it's title with the mouse).
+
+ Parameters:
+ node - the <MooTreeNode> object to select.
+ */
+
+ select: function(node) {
+ this.onClick(node); node.onClick(); // fire click events
+ if (this.selected === node) return; // already selected
+ if (this.selected) {
+ // deselect previously selected node:
+ this.selected.select(false);
+ this.onSelect(this.selected, false);
+ }
+ // select new node:
+ this.selected = node;
+ node.select(true);
+ this.onSelect(node, true);
+ },
+
+ /*
+ Property: expand
+ Expands the entire tree, recursively.
+ */
+
+ expand: function() {
+ this.root.toggle(true, true);
+ },
+
+ /*
+ Property: collapse
+ Collapses the entire tree, recursively.
+ */
+
+ collapse: function() {
+ this.root.toggle(true, false);
+ },
+
+ /*
+ Property: get
+ Retrieves the node with the given id - or null, if no node with the given id exists.
+
+ Parameters:
+ id - a string, the id of the node you wish to retrieve.
+
+ Note:
+ Node id can be assigned via the <MooTreeNode> constructor, e.g. using the <MooTreeNode.insert> method.
+ */
+
+ get: function(id) {
+ return this.index[id] || null;
+ },
+
+ /*
+ Property: adopt
+ Adopts a structure of nested ul/li/a elements as tree nodes, then removes the original elements.
+
+ Parameters:
+ id - a string representing the ul element to be adopted, or an element reference.
+ parentNode - optional, a <MooTreeNode> object under which to import the specified ul element. Defaults to the root node of the parent control.
+
+ Note:
+ The ul/li structure must be properly nested, and each li-element must contain one a-element, e.g.:
+
+ ><ul id="mytree">
+ > <li><a href="test.html">Item One</a></li>
+ > <li><a href="test.html">Item Two</a>
+ > <ul>
+ > <li><a href="test.html">Item Two Point One</a></li>
+ > <li><a href="test.html">Item Two Point Two</a></li>
+ > </ul>
+ > </li>
+ > <li><a href="test.html"><!-- icon:_doc; color:#ff0000 -->Item Three</a></li>
+ ></ul>
+
+ The "href", "target", "title" and "name" attributes of the a-tags are picked up and stored in the
+ data property of the node.
+
+ CSS-style comments inside a-tags are parsed, and treated as arguments for <MooTreeNode> constructor,
+ e.g. "icon", "openicon", "color", etc.
+ */
+
+ adopt: function(id, parentNode) {
+ if (parentNode === undefined) parentNode = this.root;
+ this.disable();
+ this._adopt(id, parentNode);
+ parentNode.update(true);
+ $(id).destroy();
+ this.enable();
+ },
+
+ _adopt: function(id, parentNode) {
+ /* adopts a structure of ul/li elements into this tree */
+ e = $(id);
+ var i=0, c = e.getChildren();
+ for (i=0; i<c.length; i++) {
+ if (c[i].nodeName == 'li') {
+ var con={text:''}, comment='', node=null, subul=null;
+ var n=0, z=0, se=null, s = c[i].getChildren();
+ for (n=0; n<s.length; n++) {
+ switch (s[n].nodeName) {
+ case 'A':
+ case 'a':
+ for (z=0; z<s[n].childNodes.length; z++) {
+ se = s[n].childNodes[z];
+ switch (se.nodeName) {
+ case '#text': con.text += se.nodeValue; break;
+ case '#comment': comment += se.nodeValue; break;
+ }
+ }
+ con.data = s[n].getProperties('href','target','title','name');
+ break;
+ case 'UL':
+ case 'ul':
+ subul = s[n];
+ break;
+ }
+ }
+ if (con.label != '') {
+ con.data.url = con.data['href']; // (for backwards compatibility)
+ if (comment != '') {
+ var bits = comment.split(';');
+ for (z=0; z<bits.length; z++) {
+ var pcs = bits[z].trim().split(':');
+ if (pcs.length == 2) con[pcs[0].trim()] = pcs[1].trim();
+ }
+ }
+ node = parentNode.insert(con);
+ if (subul) this._adopt(subul, node);
+ }
+ }
+ }
+ },
+
+ /*
+ Property: disable
+ Call this to temporarily disable visual updates -- if you need to insert/remove many nodes
+ at a time, many visual updates would normally occur. By temporarily disabling the control,
+ these visual updates will be skipped.
+
+ When you're done making changes, call <MooTreeControl.enable> to turn on visual updates
+ again, and automatically repaint all nodes that were changed.
+ */
+
+ disable: function() {
+ this.enabled = false;
+ },
+
+ /*
+ Property: enable
+ Enables visual updates again after a call to <MooTreeControl.disable>
+ */
+
+ enable: function() {
+ this.enabled = true;
+ this.root.update(true, true);
+ }
+
+});
+
+/*
+Class: MooTreeNode
+ This class implements the functionality of a single node in a <MooTreeControl>.
+
+Note:
+ You should not manually create objects of this class -- rather, you should use
+ <MooTreeControl.insert> to create nodes in the root of the tree, and then use
+ the similar function <MooTreeNode.insert> to create subnodes.
+
+ Both insert methods have a similar syntax, and both return the newly created
+ <MooTreeNode> object.
+
+Parameters:
+ options - an object. See options below.
+
+Options:
+ text - this is the displayed text of the node, and as such as is the only required parameter.
+ id - string, optional - if specified, must be a unique node identifier. Nodes with id can be retrieved using the <MooTreeControl.get> method.
+ color - string, optional - if specified, must be a six-digit hexadecimal RGB color code.
+
+ open - boolean value, defaults to false. Use true if you want the node open from the start.
+
+ icon - use this to customize the icon of the node. The following predefined values may be used: '_open', '_closed' and '_doc'. Alternatively, specify the URL of a GIF or PNG image to use - this should be exactly 18x18 pixels in size. If you have a strip of images, you can specify an image number (e.g. 'my_icons.gif#4' for icon number 4).
+ openicon - use this to customize the icon of the node when it's open.
+
+ data - an object containing whatever data you wish to associate with this node (such as an url and/or an id, etc.)
+
+Events:
+ onExpand - called when the node is expanded or collapsed: function(state) - where state is a boolean meaning true:expanded or false:collapsed.
+ onSelect - called when the node is selected or deselected: function(state) - where state is a boolean meaning true:selected or false:deselected.
+ onClick - called when the node is clicked (no arguments).
+*/
+
+var MooTreeNode = new Class({
+
+ initialize: function(options) {
+
+ this.text = options.text; // the text displayed by this node
+ this.id = options.id || null; // the node's unique id
+ this.nodes = new Array(); // subnodes nested beneath this node (MooTreeNode objects)
+ this.parent = null; // this node's parent node (another MooTreeNode object)
+ this.last = true; // a flag telling whether this node is the last (bottom) node of it's parent
+ this.control = options.control; // owner control of this node's tree
+ this.selected = false; // a flag telling whether this node is the currently selected node in it's tree
+
+ this.color = options.color || null; // text color of this node
+
+ this.data = options.data || {}; // optional object containing whatever data you wish to associate with the node (typically an url or an id)
+
+ this.onExpand = options.onExpand || new Function(); // called when the individual node is expanded/collapsed
+ this.onSelect = options.onSelect || new Function(); // called when the individual node is selected/deselected
+ this.onClick = options.onClick || new Function(); // called when the individual node is clicked
+
+ this.open = options.open ? true : false; // flag: node open or closed?
+
+ this.icon = options.icon;
+ this.openicon = options.openicon || this.icon;
+
+ // add the node to the control's node index:
+ if (this.id) this.control.index[this.id] = this;
+
+ // create the necessary divs:
+ this.div = {
+ main: new Element('div').addClass('mooTree_node'),
+ indent: new Element('div'),
+ gadget: new Element('div'),
+ icon: new Element('div'),
+ text: new Element('div').addClass('mooTree_text'),
+ sub: new Element('div')
+ }
+
+ // put the other divs under the main div:
+ this.div.main.adopt(this.div.indent);
+ this.div.main.adopt(this.div.gadget);
+ this.div.main.adopt(this.div.icon);
+ this.div.main.adopt(this.div.text);
+
+ // put the main and sub divs in the specified parent div:
+ $(options.div).adopt(this.div.main);
+ $(options.div).adopt(this.div.sub);
+
+ // attach event handler to gadget:
+ this.div.gadget._node = this;
+ this.div.gadget.onclick = this.div.gadget.ondblclick = function() {
+ this._node.toggle();
+ }
+
+ // attach event handler to icon/text:
+ this.div.icon._node = this.div.text._node = this;
+ this.div.icon.onclick = this.div.icon.ondblclick = this.div.text.onclick = this.div.text.ondblclick = function() {
+ this._node.control.select(this._node);
+ }
+
+ },
+
+ /*
+ Property: insert
+ Creates a new node, nested inside this one.
+
+ Parameters:
+ options - an object containing the same options available to the <MooTreeNode> constructor.
+
+ Returns:
+ A new <MooTreeNode> instance.
+ */
+
+ insert: function(options) {
+
+ // set the parent div and create the node:
+ options.div = this.div.sub;
+ options.control = this.control;
+ var node = new MooTreeNode(options);
+
+ // set the new node's parent:
+ node.parent = this;
+
+ // mark this node's last node as no longer being the last, then add the new last node:
+ var n = this.nodes;
+ if (n.length) n[n.length-1].last = false;
+ n.push(node);
+
+ // repaint the new node:
+ node.update();
+
+ // repaint the new node's parent (this node):
+ if (n.length == 1) this.update();
+
+ // recursively repaint the new node's previous sibling node:
+ if (n.length > 1) n[n.length-2].update(true);
+
+ return node;
+
+ },
+
+ /*
+ Property: remove
+ Removes this node, and all of it's child nodes. If you want to remove all the childnodes without removing the node itself, use <MooTreeNode.clear>
+ */
+
+ remove: function() {
+ var p = this.parent;
+ this._remove();
+ p.update(true);
+ },
+
+ _remove: function() {
+
+ // recursively remove this node's subnodes:
+ var n = this.nodes;
+ while (n.length) n[n.length-1]._remove();
+
+ // remove the node id from the control's index:
+ delete this.control.index[this.id];
+
+ // remove this node's divs:
+ this.div.main.destroy();
+ this.div.sub.destroy();
+
+ if (this.parent) {
+
+ // remove this node from the parent's collection of nodes:
+ var p = this.parent.nodes;
+ p.erase(this);
+
+ // in case we removed the parent's last node, flag it's current last node as being the last:
+ if (p.length) p[p.length-1].last = true;
+
+ }
+
+ },
+
+ /*
+ Property: clear
+ Removes all child nodes under this node, without removing the node itself.
+ To remove all nodes including this one, use <MooTreeNode.remove>
+ */
+
+ clear: function() {
+ this.control.disable();
+ while (this.nodes.length) this.nodes[this.nodes.length-1].remove();
+ this.control.enable();
+ },
+
+ /*
+ Property: update
+ Update the tree node's visual appearance.
+
+ Parameters:
+ recursive - boolean, defaults to false. If true, recursively updates all nodes beneath this one.
+ invalidated - boolean, defaults to false. If true, updates only nodes that have been invalidated while the control has been disabled.
+ */
+
+ update: function(recursive, invalidated) {
+
+ var draw = true;
+
+ if (!this.control.enabled) {
+ // control is currently disabled, so we don't do any visual updates
+ this.invalidated = true;
+ draw = false;
+ }
+
+ if (invalidated) {
+ if (!this.invalidated) {
+ draw = false; // this one is still valid, don't draw
+ } else {
+ this.invalidated = false; // we're drawing this item now
+ }
+ }
+
+ if (draw) {
+
+ var x;
+
+ // make selected, or not:
+ this.div.main.className = 'mooTree_node' + (this.selected ? ' mooTree_selected' : '');
+
+ // update indentations:
+ var p = this, i = '';
+ while (p.parent) {
+ p = p.parent;
+ i = this.getImg(p.last || !this.control.grid ? '' : 'I') + i;
+ }
+ this.div.indent.innerHTML = i;
+
+ // update the text:
+ x = this.div.text;
+ x.empty();
+ x.appendText(this.text);
+ if (this.color) x.style.color = this.color;
+
+ // update the icon or nothing if the control.mode is null:
+ this.div.icon.innerHTML = this.control.mode == null ? "" : (this.getImg( this.nodes.length ? ( this.open ? (this.openicon || this.icon || '_open') : (this.icon || '_closed') ) : ( this.icon || (this.control.mode == 'folders' ? '_closed' : '_doc') ) ));
+
+ // update the plus/minus gadget:
+ this.div.gadget.innerHTML = this.getImg( ( this.control.grid ? ( this.control.root == this ? (this.nodes.length ? 'R' : '') : (this.last?'L':'T') ) : '') + (this.nodes.length ? (this.open?'minus':'plus') : '') );
+
+ // show/hide subnodes:
+ this.div.sub.style.display = this.open ? 'block' : 'none';
+
+ }
+
+ // if recursively updating, update all child nodes:
+ if (recursive) this.nodes.forEach( function(node) {
+ node.update(true, invalidated);
+ });
+
+ },
+
+ /*
+ Property: getImg
+ Creates a new image, in the form of HTML for a DIV element with appropriate style.
+ You should not need to manually call this method. (though if for some reason you want to, you can)
+
+ Parameters:
+ name - the name of new image to create, defined by <MooTreeIcon> or located in an external file.
+
+ Returns:
+ The HTML for a new div Element.
+ */
+
+ getImg: function(name) {
+
+ var html = '<div class="mooTree_img"';
+
+ if (name != '') {
+ var img = this.control.theme;
+ var i = MooTreeIcon.indexOf(name);
+ if (i == -1) {
+ // custom (external) icon:
+ var x = name.split('#');
+ img = x[0];
+ i = (x.length == 2 ? parseInt(x[1])-1 : 0);
+ }
+ html += ' style="background-image:url(' + img + '); background-position:-' + (i*18) + 'px 0px;"';
+ }
+
+ html += "></div>";
+
+ return html;
+
+ },
+
+ /*
+ Property: toggle
+ By default (with no arguments) this function toggles the node between expanded/collapsed.
+ Can also be used to recursively expand/collapse all or part of the tree.
+
+ Parameters:
+ recursive - boolean, defaults to false. With recursive set to true, all child nodes are recursively toggle to this node's new state.
+ state - boolean. If undefined, the node's state is toggled. If true or false, the node can be explicitly opened or closed.
+ */
+
+ toggle: function(recursive, state) {
+ if (this.nodes.length == 0) {
+ // if there are no child nodes for the given node
+ // we just bail out since it doesn't make sense to toggle it
+ return;
+ }
+ this.open = (state === undefined ? !this.open : state);
+ this.update();
+
+ this.onExpand(this.open);
+ this.control.onExpand(this, this.open);
+
+ if (recursive) this.nodes.forEach( function(node) {
+ node.toggle(true, this.open);
+ }, this);
+
+ },
+
+ /*
+ Property: select
+ Called by <MooTreeControl> when the selection changes.
+ You should not manually call this method - to set the selection, use the <MooTreeControl.select> method.
+ */
+
+ select: function(state) {
+ this.selected = state;
+ this.update();
+ this.onSelect(state);
+ },
+
+ /*
+ Property: load
+ Asynchronously load an XML structure into a node of this tree.
+
+ Parameters:
+ url - string, required, specifies the URL from which to load the XML document.
+ vars - query string, optional.
+ */
+
+ load: function(url, vars) {
+
+ if (this.loading) return; // if this node is already loading, return
+ this.loading = true; // flag this node as loading
+
+ this.toggle(false, true); // expand the node to make the loader visible
+
+ this.clear();
+
+ this.insert(this.control.loader);
+
+ var f = function() {
+ new Request({
+ method: 'GET',
+ url: url,
+ onSuccess: this._loaded.bind(this),
+ onFailure: this._load_err.bind(this)
+ }).send(url, vars || '');
+ }.bind(this).delay(20);
+
+ //window.setTimeout(f.bind(this), 20); // allowing a small delay for the browser to draw the loader-icon.
+
+ },
+
+ _loaded: function(text, xml) {
+ // called on success - import nodes from the root element:
+ this.control.disable();
+ this.clear();
+ this._import(xml.documentElement);
+ this.control.enable();
+ this.loading = false;
+ },
+
+ _import: function(e) {
+ // import childnodes from an xml element:
+ var n = e.childNodes;
+ for (var i=0; i<n.length; i++) if (n[i].tagName == 'node') {
+ var opt = {data:{}};
+ var a = n[i].attributes;
+ for (var t=0; t<a.length; t++) {
+ switch (a[t].name) {
+ case 'text':
+ case 'id':
+ case 'icon':
+ case 'openicon':
+ case 'color':
+ case 'open':
+ opt[a[t].name] = a[t].value;
+ break;
+ default:
+ opt.data[a[t].name] = a[t].value;
+ }
+ }
+ var node = this.insert(opt);
+ if (node.data.load) {
+ node.open = false; // can't have a dynamically loading node that's already open!
+ node.insert(this.control.loader);
+ node.onExpand = function(state) {
+ this.load(this.data.load);
+ this.onExpand = new Function();
+ }
+ }
+ // recursively import subnodes of this node:
+ if (n[i].childNodes.length) node._import(n[i]);
+ }
+ },
+
+ _load_err: function(req) {
+ window.alert('Error loading: ' + this.text);
+ }
+
+});
Property changes on: trunk/wooly/resources/mootree.js
___________________________________________________________________
Added: svn:mime-type
+ text/plain
11 years, 1 month
r5742 - trunk/cumin/bin
by tmckay@fedoraproject.org
Author: tmckay
Date: 2013-03-15 20:48:54 +0000 (Fri, 15 Mar 2013)
New Revision: 5742
Modified:
trunk/cumin/bin/cumin-admin
Log:
Pass db connection along with cursor to handler routines so
that it can be closed if necessary. Close in handle_upgrade_schema.
Modified: trunk/cumin/bin/cumin-admin
===================================================================
--- trunk/cumin/bin/cumin-admin 2013-03-15 18:33:56 UTC (rev 5741)
+++ trunk/cumin/bin/cumin-admin 2013-03-15 20:48:54 UTC (rev 5742)
@@ -152,7 +152,7 @@
error("Only schema commands are allowed until the schema is repaired")
try:
- res = handler(app, cursor, opts, args[1:])
+ res = handler(app, conn, cursor, opts, args[1:])
if type(res) is tuple:
conn, cursor = res
conn.commit()
@@ -266,14 +266,16 @@
# Look for the next jump
curr = latest
-def handle_print_schema(app, cursor, opts, args):
+def handle_print_schema(app, conn, cursor, opts, args):
print app.admin.get_schema(),
-def handle_upgrade_schema(app, cursor, opts, args):
+def handle_upgrade_schema(app, conn, cursor, opts, args):
try:
curr = app.admin.get_schema_version(cursor)
except SchemaMissing:
error("The schema is missing, run 'cumin-admin create-schema'")
+ conn.close()
+ cursor.close()
target = app.admin.get_target_schema_version()
if curr == target:
@@ -304,7 +306,7 @@
for steps in upgrade_path:
script = os.path.join(upgrade_dir, steps[0]+"_to_"+steps[1])
print "Executing script %s" % script
-
+
res = subprocess.Popen(script, shell=True).wait()
if res != 0:
print "Script exited with error code %s" % res
@@ -336,7 +338,7 @@
print "Upgrade to schema version %s succeeded" % target
return conn, cursor
-def handle_create_schema(app, cursor, opts, args):
+def handle_create_schema(app, conn, cursor, opts, args):
try:
conn, cursor = app.admin.create_schema(cursor)
except ProgrammingError:
@@ -349,7 +351,7 @@
if conn and cursor:
return conn, cursor
-def handle_check_schema(app, cursor, opts, args):
+def handle_check_schema(app, conn, cursor, opts, args):
try:
schema_version = app.admin.check_schema(cursor)
except SchemaMissing:
@@ -359,7 +361,7 @@
print "The schema is OK (schema version %s)" % schema_version
-def handle_drop_schema(app, cursor, opts, args):
+def handle_drop_schema(app, conn, cursor, opts, args):
try:
app.admin.drop_schema(cursor)
print "The schema is dropped"
@@ -392,7 +394,7 @@
return users, roles_by_user_id
-def handle_list_users(app, cursor, opts, args):
+def handle_list_users(app, conn, cursor, opts, args):
print " ID Name Roles"
print "---- -------------------- --------------------"
@@ -418,7 +420,7 @@
if externals > 0:
print "(%i external user%s, indicated by *)" % (externals, ess(externals))
-def handle_external_user(app, cursor, opts, args):
+def handle_external_user(app, conn, cursor, opts, args):
try:
name = args[0]
except IndexError:
@@ -432,7 +434,7 @@
app.admin.add_assignment(cursor, user, role)
print "External user '%s' is added" % name
-def handle_external_sync(app, cursor, opts, args):
+def handle_external_sync(app, conn, cursor, opts, args):
print "This command is not supported at this time."
return
@@ -452,7 +454,7 @@
if errors:
print("Errors reported, check logs for details.")
-def handle_expunge_users(app, cursor, opts, args):
+def handle_expunge_users(app, conn, cursor, opts, args):
print("This will remove all users from Cumin's database.")
print("Hint: you may want to backup Cumin's user database "\
@@ -470,7 +472,7 @@
print("\nNo users removed.")
-def handle_add_role(app, cursor, opts, args):
+def handle_add_role(app, conn, cursor, opts, args):
print("\nNot implemented.")
return
@@ -490,7 +492,7 @@
print "Role '%s' is added" % name
-def handle_add_user(app, cursor, opts, args):
+def handle_add_user(app, conn, cursor, opts, args):
try:
name = args[0]
except IndexError:
@@ -515,7 +517,7 @@
app.admin.add_assignment(cursor, user, role)
print "User '%s' is added" % name
-def handle_export_users(app, cursor, opts, args):
+def handle_export_users(app, conn, cursor, opts, args):
try:
fname = args[0]
@@ -533,7 +535,7 @@
for user in users:
w.writerow([user.name, user.password] + roles_by_user_id[user._id])
-def handle_import_users(app, cursor, opts, args):
+def handle_import_users(app, conn, cursor, opts, args):
try:
fname = args[0]
@@ -593,7 +595,7 @@
warn("Role '%s' does not exist, "\
"skipping this role for user '%s'" % (role_name, info[0]))
-def handle_remove_user(app, cursor, opts, args):
+def handle_remove_user(app, conn, cursor, opts, args):
try:
name = args[0]
except IndexError:
@@ -606,7 +608,7 @@
user.delete(cursor)
print "User '%s' is removed" % name
-def handle_list_roles(app, cursor, opts, args):
+def handle_list_roles(app, conn, cursor, opts, args):
cls = app.model.com_redhat_cumin.Role
roles = cls.get_selection(cursor)
@@ -621,14 +623,14 @@
print
print "(%i user%s found)" % (count, ess(count))
-def handle_add_assignment(app, cursor, opts, args):
+def handle_add_assignment(app, conn, cursor, opts, args):
user, role = get_user_and_role(app, cursor, args)
app.admin.add_assignment(cursor, user, role)
print "User '%s' is assigned to role '%s'" % (user.name, role.name)
-def handle_remove_assignment(app, cursor, opts, args):
+def handle_remove_assignment(app, conn, cursor, opts, args):
user, role = get_user_and_role(app, cursor, args)
assignment = app.admin.get_assignment(cursor, user, role)
@@ -661,7 +663,7 @@
return user, role
-def handle_change_password(app, cursor, opts, args):
+def handle_change_password(app, conn, cursor, opts, args):
try:
user_name = args[0]
except IndexError:
@@ -678,7 +680,7 @@
user.save(cursor)
print "Password of user '%s' is changed" % user.name
-def handle_load_demo_data(app, cursor, opts, args):
+def handle_load_demo_data(app, conn, cursor, opts, args):
cls = app.model.com_redhat_cumin.BrokerGroup
for name in ("Engineering", "Marketing", "Sales"):
11 years, 1 month
r5741 - trunk/cumin/model/upgrades
by tmckay@fedoraproject.org
Author: tmckay
Date: 2013-03-15 18:33:56 +0000 (Fri, 15 Mar 2013)
New Revision: 5741
Modified:
trunk/cumin/model/upgrades/1.3a_to_1.4
Log:
Remove commment
Modified: trunk/cumin/model/upgrades/1.3a_to_1.4
===================================================================
--- trunk/cumin/model/upgrades/1.3a_to_1.4 2013-03-15 18:10:29 UTC (rev 5740)
+++ trunk/cumin/model/upgrades/1.3a_to_1.4 2013-03-15 18:33:56 UTC (rev 5741)
@@ -74,11 +74,6 @@
run 'drop table if exists \"org.apache.qpid.cluster\".\"Cluster\" cascade'
run 'drop table if exists \"org.apache.qpid.acl\".\"Acl_samples\" cascade'
run 'drop table if exists \"org.apache.qpid.acl\".\"Acl\" cascade'
-
-# select 'drop table if exists "' || schemaname || '"."' || tablename || '" cascade'
-# from pg_tables
-# where schemaname = 'com.redhat.rhm.store';
-
run 'drop table if exists \"com.redhat.rhm.store\".\"Store_samples\" cascade'
run 'drop table if exists \"com.redhat.rhm.store\".\"Journal_samples\" cascade'
run 'drop table if exists \"com.redhat.rhm.store\".\"Store\" cascade'
11 years, 1 month
r5740 - in trunk/cumin: model model/upgrades python/cumin
by tmckay@fedoraproject.org
Author: tmckay
Date: 2013-03-15 18:10:29 +0000 (Fri, 15 Mar 2013)
New Revision: 5740
Added:
trunk/cumin/model/upgrades/1.3a_to_1.4
Modified:
trunk/cumin/model/rosemary.xml
trunk/cumin/python/cumin/admin.py
Log:
Add schema upgrade script to 1.4
Modified: trunk/cumin/model/rosemary.xml
===================================================================
--- trunk/cumin/model/rosemary.xml 2013-03-14 16:04:56 UTC (rev 5739)
+++ trunk/cumin/model/rosemary.xml 2013-03-15 18:10:29 UTC (rev 5740)
@@ -159,6 +159,7 @@
<package name="com.redhat.sesame">
<class name="Sysimage">
<title>System</title>
+ <index name="nodeName" attributes="nodeName"/>
<object>
<title>%(nodeName)s</title>
Added: trunk/cumin/model/upgrades/1.3a_to_1.4
===================================================================
--- trunk/cumin/model/upgrades/1.3a_to_1.4 (rev 0)
+++ trunk/cumin/model/upgrades/1.3a_to_1.4 2013-03-15 18:10:29 UTC (rev 5740)
@@ -0,0 +1,129 @@
+#!/bin/bash
+
+function run {
+ su - postgres -c "echo $1 | psql -d cumin"
+}
+
+# Here is a query to list current com.redhat schemas
+# select distinct schemaname from pg_tables where schemaname like 'com.redhat%';
+
+# Here is one to give all the tables in a schema
+# select "tablename","schemaname" from pg_tables where schemaname like 'com.redhat%' order by "schemaname";
+
+# You can use select to generate set set of queries for you...
+
+# select 'drop sequence "' || schemaname || '"."' || tablename || '_id_seq"'
+# from pg_tables
+# where schemaname = 'org.apache.qpid.cluster';
+
+run 'drop sequence \"com.redhat.cumin.messaging\".\"BrokerGroup_id_seq\"'
+run 'drop sequence \"com.redhat.cumin.messaging\".\"BrokerGroupMapping_id_seq\"'
+run 'drop sequence \"org.apache.qpid.broker\".\"ManagementSetupState_id_seq\"'
+run 'drop sequence \"org.apache.qpid.broker\".\"System_id_seq\"'
+run 'drop sequence \"org.apache.qpid.broker\".\"Agent_id_seq\"'
+run 'drop sequence \"org.apache.qpid.broker\".\"Exchange_id_seq\"'
+run 'drop sequence \"org.apache.qpid.broker\".\"Binding_id_seq\"'
+run 'drop sequence \"org.apache.qpid.broker\".\"Subscription_id_seq\"'
+run 'drop sequence \"org.apache.qpid.broker\".\"Link_id_seq\"'
+run 'drop sequence \"org.apache.qpid.broker\".\"Bridge_id_seq\"'
+run 'drop sequence \"org.apache.qpid.broker\".\"Vhost_id_seq\"'
+run 'drop sequence \"org.apache.qpid.broker\".\"Connection_id_seq\"'
+run 'drop sequence \"org.apache.qpid.broker\".\"Session_id_seq\"'
+run 'drop sequence \"org.apache.qpid.broker\".\"Queue_id_seq\"'
+run 'drop sequence \"org.apache.qpid.broker\".\"Broker_id_seq\"'
+run 'drop sequence \"org.apache.qpid.cluster\".\"Cluster_id_seq\"'
+run 'drop sequence \"org.apache.qpid.acl\".\"Acl_id_seq\"'
+run 'drop sequence \"com.redhat.rhm.store\".\"Store_id_seq\"'
+run 'drop sequence \"com.redhat.rhm.store\".\"Journal_id_seq\"'
+
+# select 'drop table if exists "' || schemaname || '"."' || tablename || '" cascade'
+# from pg_tables
+# where schemaname = 'org.apache.qpid.cluster';
+
+run 'drop table if exists \"com.redhat.cumin.messaging\".\"BrokerGroup_samples\" cascade'
+run 'drop table if exists \"com.redhat.cumin.messaging\".\"BrokerGroupMapping_samples\" cascade'
+run 'drop table if exists \"com.redhat.cumin.messaging\".\"BrokerGroup\" cascade'
+run 'drop table if exists \"com.redhat.cumin.messaging\".\"BrokerGroupMapping\" cascade'
+run 'drop table if exists \"org.apache.qpid.broker\".\"System_samples\" cascade'
+run 'drop table if exists \"org.apache.qpid.broker\".\"Broker_samples\" cascade'
+run 'drop table if exists \"org.apache.qpid.broker\".\"Agent_samples\" cascade'
+run 'drop table if exists \"org.apache.qpid.broker\".\"Vhost_samples\" cascade'
+run 'drop table if exists \"org.apache.qpid.broker\".\"Queue_samples\" cascade'
+run 'drop table if exists \"org.apache.qpid.broker\".\"Exchange_samples\" cascade'
+run 'drop table if exists \"org.apache.qpid.broker\".\"Binding_samples\" cascade'
+run 'drop table if exists \"org.apache.qpid.broker\".\"Subscription_samples\" cascade'
+run 'drop table if exists \"org.apache.qpid.broker\".\"Connection_samples\" cascade'
+run 'drop table if exists \"org.apache.qpid.broker\".\"Link_samples\" cascade'
+run 'drop table if exists \"org.apache.qpid.broker\".\"Bridge_samples\" cascade'
+run 'drop table if exists \"org.apache.qpid.broker\".\"Session_samples\" cascade'
+run 'drop table if exists \"org.apache.qpid.broker\".\"ManagementSetupState\" cascade'
+run 'drop table if exists \"org.apache.qpid.broker\".\"ManagementSetupState_samples\" cascade'
+run 'drop table if exists \"org.apache.qpid.broker\".\"System\" cascade'
+run 'drop table if exists \"org.apache.qpid.broker\".\"Agent\" cascade'
+run 'drop table if exists \"org.apache.qpid.broker\".\"Exchange\" cascade'
+run 'drop table if exists \"org.apache.qpid.broker\".\"Binding\" cascade'
+run 'drop table if exists \"org.apache.qpid.broker\".\"Subscription\" cascade'
+run 'drop table if exists \"org.apache.qpid.broker\".\"Link\" cascade'
+run 'drop table if exists \"org.apache.qpid.broker\".\"Bridge\" cascade'
+run 'drop table if exists \"org.apache.qpid.broker\".\"Vhost\" cascade'
+run 'drop table if exists \"org.apache.qpid.broker\".\"Connection\" cascade'
+run 'drop table if exists \"org.apache.qpid.broker\".\"Session\" cascade'
+run 'drop table if exists \"org.apache.qpid.broker\".\"Queue\" cascade'
+run 'drop table if exists \"org.apache.qpid.broker\".\"Broker\" cascade'
+run 'drop table if exists \"org.apache.qpid.cluster\".\"Cluster_samples\" cascade'
+run 'drop table if exists \"org.apache.qpid.cluster\".\"Cluster\" cascade'
+run 'drop table if exists \"org.apache.qpid.acl\".\"Acl_samples\" cascade'
+run 'drop table if exists \"org.apache.qpid.acl\".\"Acl\" cascade'
+
+# select 'drop table if exists "' || schemaname || '"."' || tablename || '" cascade'
+# from pg_tables
+# where schemaname = 'com.redhat.rhm.store';
+
+run 'drop table if exists \"com.redhat.rhm.store\".\"Store_samples\" cascade'
+run 'drop table if exists \"com.redhat.rhm.store\".\"Journal_samples\" cascade'
+run 'drop table if exists \"com.redhat.rhm.store\".\"Store\" cascade'
+run 'drop table if exists \"com.redhat.rhm.store\".\"Journal\" cascade'
+
+# select 'alter table "' || schemaname || '"."' || tablename || '" drop column "_qmf_create_time" cascade' from pg_tables where
+# schemaname like 'com.redhat%' order by "schemaname";
+
+run 'alter table \"com.redhat.cumin\".\"Info\" drop column \"_qmf_create_time\" cascade'
+run 'alter table \"com.redhat.cumin\".\"UserRoleMapping\" drop column \"_qmf_create_time\" cascade'
+run 'alter table \"com.redhat.cumin\".\"Role\" drop column \"_qmf_create_time\" cascade'
+run 'alter table \"com.redhat.cumin\".\"User\" drop column \"_qmf_create_time\" cascade'
+run 'alter table \"com.redhat.cumin.grid\".\"Node\" drop column \"_qmf_create_time\" cascade'
+run 'alter table \"com.redhat.cumin.grid\".\"Limit\" drop column \"_qmf_create_time\" cascade'
+run 'alter table \"com.redhat.cumin.grid\".\"Quota\" drop column \"_qmf_create_time\" cascade'
+run 'alter table \"com.redhat.cumin.grid\".\"JobSummary\" drop column \"_qmf_create_time\" cascade'
+run 'alter table \"com.redhat.grid\".\"Master\" drop column \"_qmf_create_time\" cascade'
+run 'alter table \"com.redhat.grid\".\"Collector\" drop column \"_qmf_create_time\" cascade'
+run 'alter table \"com.redhat.grid\".\"Negotiator\" drop column \"_qmf_create_time\" cascade'
+run 'alter table \"com.redhat.grid\".\"Slot\" drop column \"_qmf_create_time\" cascade'
+run 'alter table \"com.redhat.grid\".\"Submitter\" drop column \"_qmf_create_time\" cascade'
+run 'alter table \"com.redhat.grid\".\"JobServer\" drop column \"_qmf_create_time\" cascade'
+run 'alter table \"com.redhat.grid\".\"Scheduler\" drop column \"_qmf_create_time\" cascade'
+run 'alter table \"com.redhat.grid\".\"Submission\" drop column \"_qmf_create_time\" cascade'
+run 'alter table \"com.redhat.grid\".\"Grid\" drop column \"_qmf_create_time\" cascade'
+run 'alter table \"com.redhat.sesame\".\"Sysimage\" drop column \"_qmf_create_time\" cascade'
+
+run 'alter table \"com.redhat.cumin\".\"Info\" drop column \"_qmf_delete_time\" cascade'
+run 'alter table \"com.redhat.cumin\".\"UserRoleMapping\" drop column \"_qmf_delete_time\" cascade'
+run 'alter table \"com.redhat.cumin\".\"Role\" drop column \"_qmf_delete_time\" cascade'
+run 'alter table \"com.redhat.cumin\".\"User\" drop column \"_qmf_delete_time\" cascade'
+run 'alter table \"com.redhat.cumin.grid\".\"Node\" drop column \"_qmf_delete_time\" cascade'
+run 'alter table \"com.redhat.cumin.grid\".\"Limit\" drop column \"_qmf_delete_time\" cascade'
+run 'alter table \"com.redhat.cumin.grid\".\"Quota\" drop column \"_qmf_delete_time\" cascade'
+run 'alter table \"com.redhat.cumin.grid\".\"JobSummary\" drop column \"_qmf_delete_time\" cascade'
+run 'alter table \"com.redhat.grid\".\"Master\" drop column \"_qmf_delete_time\" cascade'
+run 'alter table \"com.redhat.grid\".\"Collector\" drop column \"_qmf_delete_time\" cascade'
+run 'alter table \"com.redhat.grid\".\"Negotiator\" drop column \"_qmf_delete_time\" cascade'
+run 'alter table \"com.redhat.grid\".\"Slot\" drop column \"_qmf_delete_time\" cascade'
+run 'alter table \"com.redhat.grid\".\"Submitter\" drop column \"_qmf_delete_time\" cascade'
+run 'alter table \"com.redhat.grid\".\"JobServer\" drop column \"_qmf_delete_time\" cascade'
+run 'alter table \"com.redhat.grid\".\"Scheduler\" drop column \"_qmf_delete_time\" cascade'
+run 'alter table \"com.redhat.grid\".\"Submission\" drop column \"_qmf_delete_time\" cascade'
+run 'alter table \"com.redhat.grid\".\"Grid\" drop column \"_qmf_delete_time\" cascade'
+run 'alter table \"com.redhat.sesame\".\"Sysimage\" drop column \"_qmf_delete_time\" cascade'
+
+run 'create index \"Sysimage_nodeName_idx\" on \"com.redhat.sesame\".\"Sysimage\" \(\"nodeName\"\)'
+run 'alter table \"com.redhat.sesame\".\"Sysimage\" drop column uuid cascade'
\ No newline at end of file
Property changes on: trunk/cumin/model/upgrades/1.3a_to_1.4
___________________________________________________________________
Added: svn:executable
+ *
Modified: trunk/cumin/python/cumin/admin.py
===================================================================
--- trunk/cumin/python/cumin/admin.py 2013-03-14 16:04:56 UTC (rev 5739)
+++ trunk/cumin/python/cumin/admin.py 2013-03-15 18:10:29 UTC (rev 5740)
@@ -7,7 +7,7 @@
log = logging.getLogger("cumin.admin")
-schema_version = "1.3a"
+schema_version = "1.4"
class SchemaMissing(Exception):
pass
11 years, 1 month