r5281 - branches/play_plumage/cumin/python/cumin/messaging
by tmckay@fedoraproject.org
Author: tmckay
Date: 2012-03-30 20:32:08 +0000 (Fri, 30 Mar 2012)
New Revision: 5281
Modified:
branches/play_plumage/cumin/python/cumin/messaging/broker.py
Log:
Moved messaging specific rosemary classes created by cumin into
a com.redhat.cumin.messaging package.
Missed this file.
Modified: branches/play_plumage/cumin/python/cumin/messaging/broker.py
===================================================================
--- branches/play_plumage/cumin/python/cumin/messaging/broker.py 2012-03-30 20:27:05 UTC (rev 5280)
+++ branches/play_plumage/cumin/python/cumin/messaging/broker.py 2012-03-30 20:32:08 UTC (rev 5281)
@@ -27,7 +27,7 @@
broker = app.model.org_apache_qpid_broker.Broker
system = app.model.org_apache_qpid_broker.System
cluster = app.model.org_apache_qpid_cluster.Cluster
- mapping = app.model.com_redhat_cumin.BrokerGroupMapping
+ mapping = app.model.com_redhat_cumin_messaging.BrokerGroupMapping
super(BrokerData, self).__init__(app, vhost)
@@ -235,7 +235,7 @@
return branch.marshal()
def render_group_filters(self, session):
- cls = self.app.model.com_redhat_cumin.BrokerGroup
+ cls = self.app.model.com_redhat_cumin_messaging.BrokerGroup
groups = cls.get_selection(session.cursor)
return self._render_filters(session, groups, self.group_tmpl)
@@ -294,7 +294,7 @@
vhost = self.object.get(session)
- cls = self.app.model.com_redhat_cumin.BrokerGroupMapping
+ cls = self.app.model.com_redhat_cumin_messaging.BrokerGroupMapping
mappings = cls.get_selection(session.cursor, _broker_id=vhost._brokerRef_id)
checked_groups = [x._group_id for x in mappings]
self.groups.inputs.set(session, checked_groups)
@@ -313,7 +313,7 @@
return "Groups"
def do_get_items(self, session):
- cls = self.app.model.com_redhat_cumin.BrokerGroup
+ cls = self.app.model.com_redhat_cumin_messaging.BrokerGroup
groups = cls.get_selection(session.cursor)
return (FormInputItem(x._id, title=x.name) for x in groups)
@@ -332,11 +332,11 @@
try:
cursor = conn.cursor()
- cls = self.app.model.com_redhat_cumin.BrokerGroup
+ cls = self.app.model.com_redhat_cumin_messaging.BrokerGroup
all_groups = cls.get_selection(cursor)
selected_ids = [x._id for x in groups]
- cls = self.app.model.com_redhat_cumin.BrokerGroupMapping
+ cls = self.app.model.com_redhat_cumin_messaging.BrokerGroupMapping
for group in all_groups:
existing_mapping = cls.get_selection \
12 years
r5280 - in branches/play_plumage: cumin/bin cumin/etc cumin/model cumin/model/admin cumin/model/plumage cumin/python/cumin cumin/python/cumin/messaging mint/python/mint mint/python/mint/plumage rosemary/python/rosemary
by tmckay@fedoraproject.org
Author: tmckay
Date: 2012-03-30 20:27:05 +0000 (Fri, 30 Mar 2012)
New Revision: 5280
Added:
branches/play_plumage/cumin/bin/cumin-report
branches/play_plumage/cumin/model/admin/
branches/play_plumage/cumin/model/admin/cumin.xml
branches/play_plumage/cumin/model/admin/rosemary.xml
branches/play_plumage/cumin/model/plumage/
branches/play_plumage/cumin/model/plumage/plumage.xml
branches/play_plumage/cumin/model/plumage/rosemary.xml
branches/play_plumage/mint/python/mint/plumage/
branches/play_plumage/mint/python/mint/plumage/__init__.py
branches/play_plumage/mint/python/mint/plumage/main.py
branches/play_plumage/mint/python/mint/plumage/session.py
branches/play_plumage/mint/python/mint/plumage/update.py
Removed:
branches/play_plumage/cumin/model/plumage.xml
Modified:
branches/play_plumage/cumin/bin/cumin
branches/play_plumage/cumin/bin/cumin-admin
branches/play_plumage/cumin/bin/cumin-data
branches/play_plumage/cumin/bin/cumin-web
branches/play_plumage/cumin/etc/module.profile
branches/play_plumage/cumin/model/cumin.xml
branches/play_plumage/cumin/model/rosemary.xml
branches/play_plumage/cumin/python/cumin/config.py
branches/play_plumage/cumin/python/cumin/main.py
branches/play_plumage/cumin/python/cumin/messaging/brokergroup.py
branches/play_plumage/cumin/python/cumin/model.py
branches/play_plumage/cumin/python/cumin/parameters.py
branches/play_plumage/mint/python/mint/model.py
branches/play_plumage/rosemary/python/rosemary/model.py
Log:
Initial framework for cumin-report.
Fair amout of refactoring around config.py, rosemary/model
Modified: branches/play_plumage/cumin/bin/cumin
===================================================================
--- branches/play_plumage/cumin/bin/cumin 2012-03-30 17:17:00 UTC (rev 5279)
+++ branches/play_plumage/cumin/bin/cumin 2012-03-30 20:27:05 UTC (rev 5280)
@@ -80,18 +80,28 @@
help="Configuration section names for cumin-data instances."\
"\nEach value implies a separate cumin-data instance.")
+ parser.add_option("--reports", dest="reports", default=values.reports,
+ help="Configuration section names for cumin-report instances."\
+ "\nEach value implies a separate cumin-report instance.")
+
parser.add_option("--console", dest="console", action="store_true", default=False,
help="Log to stderr rather than master.log, no IO redirection for children.")
+ parser.add_option("--web-options", dest="web_options", default="", type=str,
+ help="Additional options string to pass to web instances."\
+ "\nEnclose in quotes, options must be --option form, splits on spaces."\
+ '\nExample: web_options="--debug --port=12345"')
+
parser.add_option("--data-options", dest="data_options", default="", type=str,
help="Additional options string to pass to data instances."\
"\nEnclose in quotes, options must be --option form, splits on spaces."\
'\nExample: data_options="--print-events=5 --print-stats"')
- parser.add_option("--web-options", dest="web_options", default="", type=str,
- help="Additional options string to pass to web instances."\
- "\nEnclose in quotes, options must be --option form, splits on spaces."\
- '\nExample: web_options="--debug --port=12345"')
+ parser.add_option("--report-options", dest="report_options", default="", type=str,
+ help="Additional options string to pass to report instances."\
+ "\nEnclose in quotes, options must be --option form, splits on spaces."\
+ '\nExample: report_options="--print-events=5 --print-stats"')
+
parser.add_option("--syslog", dest="syslog", action="store_true", default=False,
help="Log general error notfications to syslog. Intended for systemd")
@@ -139,6 +149,11 @@
for instance in options.datas.split(','):
args, prog_string = get_args("cumin-data", instance, options.init_only, console, options.data_options)
apps.append([None, args, prog_string])
+
+ if len(options.reports) > 0:
+ for instance in options.reports.split(','):
+ args, prog_string = get_args("cumin-report", instance, options.init_only, console, options.report_options)
+ apps.append([None, args, prog_string])
# Launch and babysit, do not restart if options.init_only is set
complete = 0
Modified: branches/play_plumage/cumin/bin/cumin-admin
===================================================================
--- branches/play_plumage/cumin/bin/cumin-admin 2012-03-30 17:17:00 UTC (rev 5279)
+++ branches/play_plumage/cumin/bin/cumin-admin 2012-03-30 20:27:05 UTC (rev 5280)
@@ -65,10 +65,9 @@
print "Command '%s' is unknown" % name
sys.exit(1)
- broker_uris = [x.strip() for x in opts.brokers.split(",")]
authmech = [x.strip() for x in values.common.auth.split(";")]
- app = Cumin(config.get_home(), broker_uris, opts.database, authmech=authmech)
+ app = Cumin(config.get_home(), [], opts.database, authmech=authmech)
app.check()
Modified: branches/play_plumage/cumin/bin/cumin-data
===================================================================
--- branches/play_plumage/cumin/bin/cumin-data 2012-03-30 17:17:00 UTC (rev 5279)
+++ branches/play_plumage/cumin/bin/cumin-data 2012-03-30 20:27:05 UTC (rev 5280)
@@ -137,7 +137,7 @@
mint = None
setup_initial_logging()
- parser = CuminOptionParser()
+ parser = BrokeredOptionParser()
# Add additional parameters for data
parser.add_option("--print-stats", action="store_true", default=False)
@@ -169,7 +169,8 @@
log.error("Extra arguments:" + "".join([" "+arg for arg in args]))
raise ArgError
- model_dir = os.path.join(config.home, "model")
+
+ model_dir = [os.path.join(config.home, x) for x in ("model", "model/admin")]
broker_uris = [x.strip() for x in opts.brokers.split(",")]
Added: branches/play_plumage/cumin/bin/cumin-report
===================================================================
--- branches/play_plumage/cumin/bin/cumin-report (rev 0)
+++ branches/play_plumage/cumin/bin/cumin-report 2012-03-30 20:27:05 UTC (rev 5280)
@@ -0,0 +1,243 @@
+#!/usr/bin/python
+
+import os
+import sys
+from traceback import print_exc
+
+home = os.environ.get("CUMIN_HOME", os.path.normpath("/usr/share/cumin"))
+sys.path.append(os.path.join(home, "python"))
+
+from cumin.config import *
+from cumin.util import *
+from mint.plumage.main import Plumage
+from parsley.loggingex import PipeLogThread
+from psycopg2 import OperationalError
+from cumin.admin import SchemaVersion, SchemaMissing
+from cumin.errors import CuminErrors
+
+def restore_IO():
+ sys.stderr = sys.__stderr__
+ sys.stdout = sys.__stdout__
+
+def process_classes(mint, values, section_name, on_empty=None):
+
+ return_code = CuminErrors.NO_ERROR
+ pkgs = set()
+ if values and len(values) > 0:
+
+ for cls_str in values.split(","):
+ pair = cls_str.strip().split(":")
+ if len(pair) == 2:
+ pname = pair[0]
+ cname = pair[1]
+ else:
+ log.error("Configuration section '%s',"\
+ " class name '%s' is badly formed"\
+ % (section_name, cls_str.strip()))
+ return_code = CuminErrors.PARSE_ERROR
+ break
+
+ try:
+ pkg = mint.model._packages_by_name[pname]
+ if cname == "*":
+ pkgs = pkgs.union(set(pkg._classes))
+ else:
+ try:
+ cls = pkg._classes_by_name[cname]
+ pkgs.add(cls)
+ except KeyError:
+ log.warning("Configuration section '%s',"\
+ " class '%s' is not contained in package"\
+ " '%s'" % (section_name, cname, pname))
+ except KeyError:
+ log.warning("Configuration section '%s',"\
+ " package '%s' not found" % (section_name, pname))
+ elif on_empty == "all":
+ for pkg in mint.model._packages:
+ pkgs = pkgs.union(set(pkg._classes))
+
+ return return_code, pkgs
+
+def adjust_return(passed_init, ret):
+ # Shift non-zer0 return codes left 1 bit
+ # and OR in whether or not init passed
+ if ret != 0:
+ ret = ret << 1 | passed_init
+ return ret
+
+def main():
+ passed_init = 1
+ return_code = CuminErrors.NO_ERROR
+
+ # Do our own simple option check so we can redirect IO early
+ # without worrying about other options or the behavior of optParse
+ opts = check_for_options(["--section", "--daemon"], sys.argv[1:])
+ if type(opts["--section"]) is str:
+ section_name = opts["--section"]
+ else:
+ section_name = "report"
+
+ # If the --daemon option has been set, redirect stderr and stdio through
+ # pipes. Launch a thread to read those pipes and direct the content to
+ # files with rollover control.
+ pipeThread = None
+ if opts["--daemon"]:
+ try:
+ cumin_home = os.environ.get("CUMIN_HOME", os.path.normpath("/usr/share/cumin"))
+ err_file = os.path.join(cumin_home, "log", section_name+".stderr")
+ out_file = os.path.join(cumin_home, "log", section_name+".stdout")
+
+ # Open pipes and redirect
+ err_r, err_w = os.pipe()
+ out_r, out_w = os.pipe()
+ pipeThread = PipeLogThread(descriptors=[err_r, out_r],
+ paths=[err_file, out_file],
+ call_on_fail=restore_IO)
+ pipeThread.start()
+ sys.stderr = os.fdopen(err_w, "w", 0)
+ sys.stdout = os.fdopen(out_w, "w", 0)
+ except:
+ print_exc()
+ pipeThread = None
+
+ class ArgError(Exception):
+ pass
+
+ try:
+ mint = None
+ setup_initial_logging()
+
+ parser = PlumageOptionParser()
+
+ # Add additional parameters for report
+ parser.add_option("--print-stats", action="store_true", default=False)
+ parser.add_option("--print-events", type="int", default=0, metavar="LEVEL")
+ parser.add_option("--section", default="report")
+ parser.add_option("--daemon", action="store_true", default=False)
+ parser.add_option("--no-vacuum", dest="vacuum_enabled", action="store_false")
+ parser.add_option("--no-expire", dest="expire_enabled", action="store_false")
+
+ # Get options
+ opts, args = parser.parse_args()
+
+ # --section controls which section is read from the config file
+ # If a section other than "report" is specified, require it to exist
+ config = CuminReportConfig(opts.section, strict_section = opts.section != "report")
+
+ # There might be other sections returned from config.parse() but
+ # currently we don't care about them...
+ values = getattr(config.parse(), opts.section)
+
+ # Use the config values as defaults for unspecified options
+ apply_defaults(values, opts)
+
+ setup_operational_logging(opts,
+ values.log_max_mb,
+ values.log_max_archives)
+
+ if len(args) != 0:
+ log.error("Extra arguments:" + "".join([" "+arg for arg in args]))
+ raise ArgError
+
+ model_dir = [os.path.join(config.home, x) for x in ("model/admin", "model/plumage")]
+
+ broker_uris = []
+# broker_uris = [x.strip() for x in opts.brokers.split(",")]
+
+ mint = Plumage(model_dir, broker_uris, opts.database)
+
+ mint.print_event_level = opts.print_events
+
+ mint.expire_enabled = opts.expire_enabled
+ mint.expire_thread.interval = values.expire_interval
+ mint.expire_thread.threshold = values.expire_threshold
+
+ mint.vacuum_enabled = opts.vacuum_enabled
+ mint.vacuum_thread.interval = values.vacuum_interval
+
+ mint.check()
+ mint.init()
+
+ # Handle QMF class binding options
+ if values.include_classes or values.exclude_classes:
+ return_code, includes = process_classes(mint,
+ values.include_classes,
+ opts.section, on_empty="all")
+
+ return_code, excludes = process_classes(mint,
+ values.exclude_classes,
+ opts.section)
+
+ mint.qmf_classes = includes.difference(excludes)
+
+
+ # If init_only was set or we failed init, don't proceed...
+ if not opts.init_only and not return_code:
+ passed_init = 0
+
+ mint.start()
+ stats = mint.update_thread.stats
+ count = 0
+
+ if opts.print_stats:
+ print "[Starred columns are the number of events per second]"
+
+ while True:
+ if count % 20 == 0:
+ stats.print_headings()
+
+ count += 1
+
+ stats.print_values()
+
+ sleep(5)
+ else:
+ while True:
+ sleep(86400)
+
+ except KeyboardInterrupt:
+ log.info("Received shutdown signal")
+
+ except SystemExit:
+ if "--help" not in sys.argv:
+ log.error("Error in options")
+ return_code = CuminErrors.PARSE_ERROR
+
+ except ArgError:
+ return_code = CuminErrors.PARSE_ERROR
+
+ except OperationalError:
+ # Failed to talk to the database on check()
+ log.info("Run 'cumin-database check' as root for more information.")
+ return_code = CuminErrors.DATABASE_ERROR
+
+ except SchemaMissing:
+ log.info("Run 'cumin-admin create-schema' as root")
+ return_code = CuminErrors.SCHEMA_ERROR
+
+ except SchemaVersion:
+ log.info("Run 'cumin-admin upgrade-schema' as root")
+ return_code = CuminErrors.SCHEMA_VER_ERROR
+
+ except:
+ print_exc()
+ return_code = CuminErrors.UNHANDLED_ERROR
+
+ if mint:
+ mint.stop()
+ if pipeThread:
+ pipeThread.stop()
+ log.info("about to call logging shutdown")
+ logging.shutdown()
+ return adjust_return(passed_init, return_code)
+
+def make_ctrl_c(sig, frame):
+ raise KeyboardInterrupt
+
+if __name__ == "__main__":
+ try:
+ import signal
+ signal.signal(signal.SIGTERM, make_ctrl_c)
+ sys.exit(main())
+ except KeyboardInterrupt:
+ sys.exit(0)
Property changes on: branches/play_plumage/cumin/bin/cumin-report
___________________________________________________________________
Added: svn:executable
+ *
Modified: branches/play_plumage/cumin/bin/cumin-web
===================================================================
--- branches/play_plumage/cumin/bin/cumin-web 2012-03-30 17:17:00 UTC (rev 5279)
+++ branches/play_plumage/cumin/bin/cumin-web 2012-03-30 20:27:05 UTC (rev 5280)
@@ -95,7 +95,7 @@
setup_initial_logging()
- parser = CuminOptionParser()
+ parser = BrokeredOptionParser()
# Add additional parameters for web
parser.add_option("--host")
Modified: branches/play_plumage/cumin/etc/module.profile
===================================================================
--- branches/play_plumage/cumin/etc/module.profile 2012-03-30 17:17:00 UTC (rev 5279)
+++ branches/play_plumage/cumin/etc/module.profile 2012-03-30 20:27:05 UTC (rev 5280)
@@ -1,3 +1,3 @@
export PYTHONPATH="${PWD}/python:${PYTHONPATH}"
-export PATH="${PWD}/bin:${PATH}"
+export PATH="${PWD}/bin:${PWD}/bin/test:${PATH}"
export CUMIN_HOME="${PWD}/instance"
Added: branches/play_plumage/cumin/model/admin/cumin.xml
===================================================================
--- branches/play_plumage/cumin/model/admin/cumin.xml (rev 0)
+++ branches/play_plumage/cumin/model/admin/cumin.xml 2012-03-30 20:27:05 UTC (rev 5280)
@@ -0,0 +1,21 @@
+<model>
+ <package name="com.redhat.cumin">
+ <class name="Info">
+ <property name="schema_version" type="sstr"/>
+ </class>
+
+ <class name="User">
+ <property name="name" type="sstr" index="y"/>
+ <property name="password" type="sstr"/>
+ </class>
+
+ <class name="Role">
+ <property name="name" type="sstr" index="y"/>
+ </class>
+
+ <class name="UserRoleMapping">
+ <property name="user" references="User" index="y"/>
+ <property name="role" references="Role" index="y"/>
+ </class>
+ </package>
+</model>
Added: branches/play_plumage/cumin/model/admin/rosemary.xml
===================================================================
--- branches/play_plumage/cumin/model/admin/rosemary.xml (rev 0)
+++ branches/play_plumage/cumin/model/admin/rosemary.xml 2012-03-30 20:27:05 UTC (rev 5280)
@@ -0,0 +1,7 @@
+<model>
+ <package name="com.redhat.cumin" persistent="y">
+ <class name="User">
+ <property name="name" unique="y"/>
+ </class>
+ </package>
+</model>
Modified: branches/play_plumage/cumin/model/cumin.xml
===================================================================
--- branches/play_plumage/cumin/model/cumin.xml 2012-03-30 17:17:00 UTC (rev 5279)
+++ branches/play_plumage/cumin/model/cumin.xml 2012-03-30 20:27:05 UTC (rev 5280)
@@ -1,5 +1,5 @@
<model>
- <package name="com.redhat.cumin">
+ <package name="com.redhat.cumin.messaging">
<class name="BrokerGroup">
<property name="name" type="sstr"/>
<property name="description" type="lstr" optional="y"/>
@@ -9,24 +9,6 @@
<property name="broker" type="objId" references="org.apache.qpid.broker:Broker"/>
<property name="group" type="objId" references="BrokerGroup"/>
</class>
-
- <class name="Info">
- <property name="schema_version" type="sstr"/>
- </class>
-
- <class name="User">
- <property name="name" type="sstr" index="y"/>
- <property name="password" type="sstr"/>
- </class>
-
- <class name="Role">
- <property name="name" type="sstr" index="y"/>
- </class>
-
- <class name="UserRoleMapping">
- <property name="user" references="User" index="y"/>
- <property name="role" references="Role" index="y"/>
- </class>
</package>
<package name="com.redhat.cumin.grid">
Added: branches/play_plumage/cumin/model/plumage/plumage.xml
===================================================================
--- branches/play_plumage/cumin/model/plumage/plumage.xml (rev 0)
+++ branches/play_plumage/cumin/model/plumage/plumage.xml 2012-03-30 20:27:05 UTC (rev 5280)
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<schema package="com.redhat.grid.plumage">
+ <class name="OSUtil" qmf_headers="False">
+ <property name="uuid" index="y" type="uuid" access="RC" desc="UUID of System Image"/>
+
+ <property name="osName" type="sstr" access="RO" desc="Operating System Name" />
+
+ <statistic name="avail" type="uint32" unit="uint32" />
+ <statistic name="used" type="uint32" unit="uint32" />
+ </class>
+</schema>
Added: branches/play_plumage/cumin/model/plumage/rosemary.xml
===================================================================
--- branches/play_plumage/cumin/model/plumage/rosemary.xml (rev 0)
+++ branches/play_plumage/cumin/model/plumage/rosemary.xml 2012-03-30 20:27:05 UTC (rev 5280)
@@ -0,0 +1,18 @@
+<model>
+ <package name="com.redhat.grid.plumage">
+ <class name="OSUtil">
+ <property name="osName">
+ <title>OS</title>
+ </property>
+
+ <statistic name="used">
+ <title>Used</title>
+ </statistic>
+
+ <statistic name="avail">
+ <title>Available</title>
+ </statistic>
+ </class>
+ </package>
+
+</model>
Deleted: branches/play_plumage/cumin/model/plumage.xml
===================================================================
--- branches/play_plumage/cumin/model/plumage.xml 2012-03-30 17:17:00 UTC (rev 5279)
+++ branches/play_plumage/cumin/model/plumage.xml 2012-03-30 20:27:05 UTC (rev 5280)
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<schema package="com.redhat.grid.plumage">
- <class name="OSUtil" qmf_headers="False">
- <property name="uuid" index="y" type="uuid" access="RC" desc="UUID of System Image"/>
-
- <property name="osName" type="sstr" access="RO" desc="Operating System Name" />
-
- <statistic name="avail" type="uint32" unit="uint32" />
- <statistic name="used" type="uint32" unit="uint32" />
- </class>
-</schema>
Modified: branches/play_plumage/cumin/model/rosemary.xml
===================================================================
--- branches/play_plumage/cumin/model/rosemary.xml 2012-03-30 17:17:00 UTC (rev 5279)
+++ branches/play_plumage/cumin/model/rosemary.xml 2012-03-30 20:27:05 UTC (rev 5280)
@@ -1,10 +1,4 @@
<model>
- <package name="com.redhat.cumin" persistent="y">
- <class name="User">
- <property name="name" unique="y"/>
- </class>
- </package>
-
<package name="com.redhat.cumin.grid">
<class name="JobSummary">
<property name="GlobalJobId">
@@ -204,7 +198,7 @@
</class>
</package>
- <package name="com.redhat.cumin">
+ <package name="com.redhat.cumin.messaging">
<class name="BrokerGroup">
<title>Broker group</title>
@@ -547,20 +541,4 @@
</class>
</package>
- <package name="com.redhat.grid.plumage">
- <class name="OSUtil">
- <property name="osName">
- <title>OS</title>
- </property>
-
- <statistic name="used">
- <title>Used</title>
- </statistic>
-
- <statistic name="avail">
- <title>Available</title>
- </statistic>
- </class>
- </package>
-
</model>
Modified: branches/play_plumage/cumin/python/cumin/config.py
===================================================================
--- branches/play_plumage/cumin/python/cumin/config.py 2012-03-30 17:17:00 UTC (rev 5279)
+++ branches/play_plumage/cumin/python/cumin/config.py 2012-03-30 20:27:05 UTC (rev 5280)
@@ -16,90 +16,7 @@
if not os.path.isdir(self.home):
raise Exception("Home path '%s' is not a directory")
-
- test = CuminConfigSection(self, "test")
- test.log_file.default = os.path.join(self.home, "log", "test.log")
-
- def create_web_section(self, name, strict_section):
- web = CuminConfigSection(self, name, strict_section)
- web.log_file.default = os.path.join(self.home, "log", name + ".log")
-
- param = ConfigParameter(web, "update-interval", int)
- param.default = 10
-
- param = ConfigParameter(web, "max-qmf-table-sort", int)
- param.default = 1000
-
- param = ConfigParameter(web, "host", str)
- param.default = "localhost"
-
- param = ConfigParameter(web, "port", int)
- param.default = 45672
-
- param = ConfigParameter(web, "operator-email", str)
-
- param = ConfigParameter(web, "user", str)
-
- param = ConfigParameter(web, "request-memory", int)
- param.default = 512 # MB
- param = ConfigParameter(web, "request-memory-vm", int)
- param.default = 512 # MB
- param = ConfigParameter(web, "request-disk", int)
- param.default = 1024 #MB
- param = ConfigParameter(web, "request-disk-vm", int)
- param.default = 5 * 1024 #MB
-
- param = ConfigParameter(web, "persona", str)
- param.default = "grid"
- param = ConfigParameter(web, "fast-view-attributes", str)
- param.default = "JobStatus,Cmd,Args,ExitStatus,JobStartDate,LastRemoteHost,LastJobStatus,Owner"
-
- param = ConfigParameter(web, "notification-timeout", int)
- param.default = 180
-
- # Hidden parameter used to force html doctype rather than xhtml
- # This is hopefully a temporary workaround so that selenium can
- # be used to do some automated testing against cumin
- param = ConfigParameter(web, "force-html-doctype", bool)
- param.default = False
-
- def create_data_section(self, name, strict_section):
- data = CuminConfigSection(self, name, strict_section)
- data.log_file.default = os.path.join(self.home, "log", name + ".log")
-
- param = ConfigParameter(data, "include-classes", str)
- param = ConfigParameter(data, "exclude-classes", str)
- param = ConfigParameter(data, "agents", str)
-
- param = ConfigParameter(data, "expire-enabled", bool)
- param.default = True
-
- param = ConfigParameter(data, "expire-interval", int)
- param.default = 60 * 60 # 1 hour
-
- param = ConfigParameter(data, "expire-threshold", int)
- param.default = 24 * 60 * 60 # 1 day
-
- param = ConfigParameter(data, "vacuum-enabled", bool)
- param.default = True
-
- param = ConfigParameter(data, "vacuum-interval", int)
- param.default = 60 * 60 # 1 hour
-
- def create_master_section(self, name, strict_section):
- '''
- Creates a blank master section.
- CuminConfigSection values are not interesting to the master
- '''
-
- master = ConfigSection(self, name, strict_section)
- param = ConfigParameter(master, "datas", str)
- param.default = "data"
-
- param = ConfigParameter(master, "webs", str)
- param.default = "web"
-
def get_home(self):
return self.home
@@ -130,20 +47,59 @@
def __init__(self, section_name="web", strict_section="False"):
super(CuminWebConfig, self).__init__()
- self.create_web_section(section_name, strict_section)
+ web = CuminWebConfigSection(self, section_name, strict_section)
+ web.log_file.default = os.path.join(self.home, "log",
+ section_name + ".log")
+
+def _common_data_section(self, data, name):
+ data.log_file.default = os.path.join(self.home, "log", name + ".log")
+
+ param = ConfigParameter(data, "include-classes", str)
+ param = ConfigParameter(data, "exclude-classes", str)
+
+ param = ConfigParameter(data, "expire-enabled", bool)
+ param.default = True
+
+ param = ConfigParameter(data, "expire-interval", int)
+ param.default = 60 * 60 # 1 hour
+
+ param = ConfigParameter(data, "expire-threshold", int)
+ param.default = 24 * 60 * 60 # 1 day
+
+ param = ConfigParameter(data, "vacuum-enabled", bool)
+ param.default = True
+
+ param = ConfigParameter(data, "vacuum-interval", int)
+ param.default = 60 * 60 # 1 hour
class CuminDataConfig(CuminConfig):
def __init__(self, section_name="data", strict_section=False):
super(CuminDataConfig, self).__init__()
- self.create_data_section(section_name, strict_section)
+ data = CuminDataConfigSection(self, section_name, strict_section)
+ _common_data_section(self, data, section_name)
+class CuminReportConfig(CuminConfig):
+ def __init__(self, section_name="report", strict_section=False):
+ super(CuminReportConfig, self).__init__()
+
+ data = CuminDataConfigSection(self, section_name, strict_section)
+ _common_data_section(self, data, section_name)
+
class CuminMasterConfig(CuminConfig):
def __init__(self, section_name="master", strict_section=False):
super(CuminMasterConfig, self).__init__()
- self.create_master_section(section_name, strict_section)
+ master = ConfigSection(self, section_name, strict_section)
+ param = ConfigParameter(master, "datas", str)
+ param.default = "data"
+ param = ConfigParameter(master, "webs", str)
+ param.default = "web"
+
+ param = ConfigParameter(master, "reports", str)
+ param.default = ""
+
class CuminConfigSection(ConfigSection):
def __init__(self, config, name, strict_section=False):
super(CuminConfigSection, self).__init__(config, name, strict_section)
@@ -151,16 +107,42 @@
param = ConfigParameter(self, "database", str)
param.default = "dbname=cumin user=cumin host=localhost"
+ # Put this here, because authentication is something that
+ # might need to be done commonly
+ param = ConfigParameter(self, "auth", str)
+ param.default = 'internal'
+
+ self.log_file = ConfigParameter(self, "log-file", str)
+
+ param = ConfigParameter(self, "log-level", str)
+ param.default = "info"
+
+ param = ConfigParameter(self, "log-max-mb", float)
+ param.default = 10
+
+ param = ConfigParameter(self, "log-max-archives", int)
+ param.default = 1
+
+ param = ConfigParameter(self, "debug", bool)
+ param.default = False
+
+class BrokeredConfigSection(CuminConfigSection):
+ def __init__(self, config, name, strict_section=False):
+ super(BrokeredConfigSection, self).__init__(config, name,
+ strict_section)
+
param = ConfigParameter(self, "brokers", str)
param.default = "amqp://localhost"
- param = ConfigParameter(self, "auth", str)
- param.default = 'internal'
-
# Leave default set to None, which is equivalent to
# previous behavior
param = ConfigParameter(self, "sasl-mech-list", str)
+class CuminWebConfigSection(BrokeredConfigSection):
+ def __init__(self, config, name, strict_section=False):
+ super(CuminWebConfigSection, self).__init__(config, name,
+ strict_section)
+
param = ConfigParameter(self, "wallaby-broker", str)
param.default = ""
@@ -190,20 +172,60 @@
param = ConfigParameter(self, "aviary-suds-logs", bool)
param.default = False
- self.log_file = ConfigParameter(self, "log-file", str)
+ param = ConfigParameter(self, "update-interval", int)
+ param.default = 10
- param = ConfigParameter(self, "log-level", str)
- param.default = "info"
+ param = ConfigParameter(self, "max-qmf-table-sort", int)
+ param.default = 1000
- param = ConfigParameter(self, "log-max-mb", float)
- param.default = 10
+ param = ConfigParameter(self, "host", str)
+ param.default = "localhost"
- param = ConfigParameter(self, "log-max-archives", int)
- param.default = 1
+ param = ConfigParameter(self, "port", int)
+ param.default = 45672
- param = ConfigParameter(self, "debug", bool)
+ param = ConfigParameter(self, "operator-email", str)
+
+ param = ConfigParameter(self, "user", str)
+
+ param = ConfigParameter(self, "request-memory", int)
+ param.default = 512 # MB
+ param = ConfigParameter(self, "request-memory-vm", int)
+ param.default = 512 # MB
+ param = ConfigParameter(self, "request-disk", int)
+ param.default = 1024 #MB
+ param = ConfigParameter(self, "request-disk-vm", int)
+ param.default = 5 * 1024 #MB
+
+ param = ConfigParameter(self, "persona", str)
+ param.default = "grid"
+
+ param = ConfigParameter(self, "fast-view-attributes", str)
+ param.default = "JobStatus,Cmd,Args,ExitStatus,JobStartDate,LastRemoteHost,LastJobStatus,Owner"
+
+ param = ConfigParameter(self, "notification-timeout", int)
+ param.default = 180
+
+ # Hidden parameter used to force html doctype rather than xhtml
+ # This is hopefully a temporary workaround so that selenium can
+ # be used to do some automated testing against cumin
+ param = ConfigParameter(self, "force-html-doctype", bool)
param.default = False
+class CuminDataConfigSection(BrokeredConfigSection):
+ def __init__(self, config, name, strict_section=False):
+ super(CuminDataConfigSection, self).__init__(config, name,
+ strict_section)
+ param = ConfigParameter(self, "agents", str)
+
+class CuminReportConfigSection(CuminConfigSection):
+ def __init__(self, config, name, strict_section=False):
+ super(CuminReportConfigSection, self).__init__(config, name,
+ strict_section)
+
+ param = ConfigParameter(self, "plumage_server", str)
+ param.default = "localhost"
+
class CuminOptionParser(OptionParser,object):
def __init__(self):
OptionParser.__init__(self)
@@ -214,10 +236,25 @@
# section named in --section, via apply_defaults()
self.add_option("--debug", action="store_true")
self.add_option("--database")
- self.add_option("--brokers")
self.add_option("--log-file")
self.add_option("--log-level")
+class BrokeredOptionParser(CuminOptionParser):
+ def __init__(self):
+ CuminOptionParser.__init__(self)
+
+ # Defaults for these come later from the config
+ # section named in --section, via apply_defaults()
+ self.add_option("--brokers")
+
+class PlumageOptionParser(CuminOptionParser):
+ def __init__(self):
+ CuminOptionParser.__init__(self)
+
+ # Defaults for these come later from the config
+ # section named in --section, via apply_defaults()
+ self.add_option("--server")
+
def apply_defaults(values, opts):
for k, v in opts.__dict__.iteritems():
if v == None and k in values:
Modified: branches/play_plumage/cumin/python/cumin/main.py
===================================================================
--- branches/play_plumage/cumin/python/cumin/main.py 2012-03-30 17:17:00 UTC (rev 5279)
+++ branches/play_plumage/cumin/python/cumin/main.py 2012-03-30 20:27:05 UTC (rev 5280)
@@ -39,7 +39,7 @@
self.home = home
self.authmech = authmech
- model_dir = os.path.join(self.home, "model")
+ model_dir = [os.path.join(self.home, x) for x in ("model/admin", "model")]
self.model = CuminModel(self, model_dir)
self.session = CuminSession(self, broker_uris)
Modified: branches/play_plumage/cumin/python/cumin/messaging/brokergroup.py
===================================================================
--- branches/play_plumage/cumin/python/cumin/messaging/brokergroup.py 2012-03-30 17:17:00 UTC (rev 5279)
+++ branches/play_plumage/cumin/python/cumin/messaging/brokergroup.py 2012-03-30 20:27:05 UTC (rev 5280)
@@ -18,7 +18,7 @@
class BrokerGroupSelector(ObjectSelector):
def __init__(self, app, name):
- cls = app.model.com_redhat_cumin.BrokerGroup
+ cls = app.model.com_redhat_cumin_messaging.BrokerGroup
super(BrokerGroupSelector, self).__init__(app, name, cls)
@@ -54,7 +54,7 @@
class BrokerGroupFrame(ObjectFrame):
def __init__(self, app, name):
- cls = app.model.com_redhat_cumin.BrokerGroup
+ cls = app.model.com_redhat_cumin_messaging.BrokerGroup
super(BrokerGroupFrame, self).__init__(app, name, cls)
@@ -106,7 +106,7 @@
try:
cursor = conn.cursor()
- cls = self.app.model.com_redhat_cumin.BrokerGroup
+ cls = self.app.model.com_redhat_cumin_messaging.BrokerGroup
group = cls.create_object(cursor)
group.name = name
Modified: branches/play_plumage/cumin/python/cumin/model.py
===================================================================
--- branches/play_plumage/cumin/python/cumin/model.py 2012-03-30 17:17:00 UTC (rev 5279)
+++ branches/play_plumage/cumin/python/cumin/model.py 2012-03-30 20:27:05 UTC (rev 5280)
@@ -40,9 +40,12 @@
def check(self):
log.info("Checking %s", self)
- assert os.path.isdir(self.model_dir)
+ if not type(self.model_dir) in (list, tuple):
+ self.model_dir = [self.model_dir]
- log.debug("Model dir exists at '%s'", self.model_dir)
+ for dirs in self.model_dir:
+ assert os.path.isdir(dirs)
+ log.debug("Model dir exists at '%s'", dirs)
def init(self):
log.info("Initializing %s", self)
Modified: branches/play_plumage/cumin/python/cumin/parameters.py
===================================================================
--- branches/play_plumage/cumin/python/cumin/parameters.py 2012-03-30 17:17:00 UTC (rev 5279)
+++ branches/play_plumage/cumin/python/cumin/parameters.py 2012-03-30 20:27:05 UTC (rev 5280)
@@ -82,7 +82,7 @@
class NewBrokerGroupParameter(Parameter):
def do_unmarshal(self, string):
id = int(string)
- cls = self.app.model.com_redhat_cumin.BrokerGroup
+ cls = self.app.model.com_redhat_cumin_messaging.BrokerGroup
cursor = self.app.database.get_read_cursor()
Modified: branches/play_plumage/mint/python/mint/model.py
===================================================================
--- branches/play_plumage/mint/python/mint/model.py 2012-03-30 17:17:00 UTC (rev 5279)
+++ branches/play_plumage/mint/python/mint/model.py 2012-03-30 20:27:05 UTC (rev 5280)
@@ -20,11 +20,14 @@
def check(self):
log.info("Checking %s", self)
+
+ if not type(self.model_dir) in (tuple, list):
+ self.model_dir = [self.model_dir]
- assert os.path.isdir(self.model_dir)
+ for dirs in self.model_dir:
+ assert os.path.isdir(dirs)
+ log.debug("Model dir exists at '%s'", dirs)
- log.debug("Model dir exists at '%s'", self.model_dir)
-
def init(self):
log.info("Initializing %s", self)
Added: branches/play_plumage/mint/python/mint/plumage/__init__.py
===================================================================
Added: branches/play_plumage/mint/python/mint/plumage/main.py
===================================================================
--- branches/play_plumage/mint/python/mint/plumage/main.py (rev 0)
+++ branches/play_plumage/mint/python/mint/plumage/main.py 2012-03-30 20:27:05 UTC (rev 5280)
@@ -0,0 +1,85 @@
+from mint.database import MintDatabase
+from mint.expire import ExpireThread
+from mint.model import MintModel
+from mint.vacuum import VacuumThread
+from session import PlumageSession
+from update import UpdateThread
+from cumin.admin import CuminAdmin
+#from util import *
+
+import logging
+
+log = logging.getLogger("mint.plumage")
+
+class Plumage(object):
+ def __init__(self, model_dir, server_url, database_dsn):
+
+ # Can we just use a different model dir here?
+ # That would control visible packages, vacuuming, etc.
+ self.model = MintModel(self, model_dir)
+ self.model.sql_logging_enabled = False
+
+ self.database = MintDatabase(self, database_dsn)
+ self.admin = CuminAdmin(self)
+ self.update_thread = UpdateThread(self)
+ self.session = PlumageSession(self, server_url)
+
+ self.expire_enabled = False
+ self.expire_thread = ExpireThread(self)
+
+ self.vacuum_enabled = False
+ self.vacuum_thread = VacuumThread(self)
+
+ self.print_event_level = 0
+
+ self.packages = []
+
+ def check(self):
+ log.info("Checking %s", self)
+
+ self.model.check()
+ self.database.check()
+
+ def init(self):
+ log.info("Initializing %s", self)
+
+ def state(cond):
+ return cond and "enabled" or "disabled"
+
+ log.info("Expiration is %s", state(self.expire_enabled))
+ log.info("Vacuum is %s", state(self.vacuum_enabled))
+
+ self.model.init()
+ self.database.init()
+
+ self.update_thread.init()
+ self.session.init()
+ #self.expire_thread.init()
+ #self.vacuum_thread.init()
+
+ def start(self):
+ log.info("Starting %s", self)
+
+ self.update_thread.start()
+ self.session.start()
+
+ #if self.expire_enabled:
+ # self.expire_thread.start()
+
+ #if self.vacuum_enabled:
+ # self.vacuum_thread.start()
+
+ def stop(self):
+ log.info("Stopping %s", self)
+
+ self.update_thread.stop()
+ self.session.stop()
+
+ #if self.expire_enabled:
+ # self.expire_thread.stop()
+
+ #if self.vacuum_enabled:
+ # self.vacuum_thread.stop()
+
+ def __repr__(self):
+ return self.__class__.__name__
Added: branches/play_plumage/mint/python/mint/plumage/session.py
===================================================================
--- branches/play_plumage/mint/python/mint/plumage/session.py (rev 0)
+++ branches/play_plumage/mint/python/mint/plumage/session.py 2012-03-30 20:27:05 UTC (rev 5280)
@@ -0,0 +1,89 @@
+import logging
+
+from mint.util import MintDaemonThread
+from time import sleep
+
+log = logging.getLogger("mint.plumage.session")
+
+class PlumageSession(object):
+ def __init__(self, app, server_url):
+ self.app = app
+ self.server_url = server_url
+
+ def check(self):
+ log.info("Checking %s", self)
+
+ def init(self):
+ log.info("Initializing %s", self)
+
+ def start(self):
+ log.info("Starting %s", self)
+
+ def stop(self):
+ log.info("Stopping %s", self)
+
+ def __repr__(self):
+ return "%s(%s)" % (self.__class__.__name__, self.server_url)
+
+class PlumageSessionThread(MintDaemonThread):
+ def __init__(self, app):
+ super(PumageSessionThread, self).__init__(app)
+
+ def run(self):
+ while True:
+ if self.stop_requested:
+ break
+
+ # We create objects here
+ sleep(5)
+
+'''
+class MintConsole(Console):
+ def __init__(self, model):
+ self.model = model
+
+ def brokerConnected(self, qmf_broker):
+ message = "Broker %s:%i is connected"
+ self.model.print_event(1, message, qmf_broker.host, qmf_broker.port)
+
+ def brokerInfo(self, qmf_broker):
+ message = "Broker info from %s:%i"
+ self.model.print_event(1, message, qmf_broker.host, qmf_broker.port)
+
+ def brokerDisconnected(self, qmf_broker):
+ message = "Broker %s:%i is disconnected"
+ self.model.print_event(1, message, qmf_broker.host, qmf_broker.port)
+
+ def newAgent(self, qmf_agent):
+ self.model.print_event(3, "Creating %s", qmf_agent)
+
+ up = AgentUpdate(self.model, qmf_agent)
+ self.model.app.update_thread.enqueue(up)
+
+ def delAgent(self, qmf_agent):
+ self.model.print_event(3, "Deleting %s", qmf_agent)
+
+ up = AgentDelete(self.model, qmf_agent)
+ self.model.app.update_thread.enqueue(up)
+
+ def heartbeat(self, qmf_agent, timestamp):
+ message = "Heartbeat from %s at %s"
+ self.model.print_event(5, message, qmf_agent, timestamp)
+
+ up = AgentUpdate(self.model, qmf_agent)
+ self.model.app.update_thread.enqueue(up)
+
+ def newPackage(self, name):
+ self.model.print_event(2, "New package %s", name)
+
+ def newClass(self, kind, classKey):
+ self.model.print_event(2, "New class %s", classKey)
+
+ def objectProps(self, broker, qmf_object):
+ up = ObjectUpdate(self.model, qmf_object)
+ self.model.app.update_thread.enqueue(up)
+
+ def objectStats(self, broker, qmf_object):
+ up = ObjectUpdate(self.model, qmf_object)
+ self.model.app.update_thread.enqueue(up)
+'''
Added: branches/play_plumage/mint/python/mint/plumage/update.py
===================================================================
--- branches/play_plumage/mint/python/mint/plumage/update.py (rev 0)
+++ branches/play_plumage/mint/python/mint/plumage/update.py 2012-03-30 20:27:05 UTC (rev 5280)
@@ -0,0 +1,363 @@
+import copy
+import resource
+import pickle
+
+from psycopg2 import IntegrityError, TimestampFromTicks
+from psycopg2.extensions import cursor as Cursor
+from rosemary.model import *
+
+from mint.model import *
+from mint.util import *
+
+log = logging.getLogger("mint.plumage.update")
+
+sample_window_min = 60
+sample_window_max = 60 * 5
+
+class UpdateThread(MintDaemonThread):
+ def __init__(self, app):
+ super(UpdateThread, self).__init__(app)
+
+ self.updates = ConcurrentQueue(maxsize=1000)
+ self.stats = UpdateStats(self.app)
+
+ self.conn = None
+ self.cursor = None
+
+ self.halt_on_error = False
+
+ def _delete_all_objects(self):
+ def loop_body(cls):
+ if cls._storage != "none":
+ if cls.check_persistent():
+ log.debug("Skipping persistent class " + str(cls))
+ else:
+ cls.delete_selection(self.cursor)
+ self.cursor.connection.commit()
+
+ log.debug("Delete all objects by bound packages " + str(self.app.packages))
+ for pkg in self.app.packages:
+ for cls in pkg._classes:
+ loop_body(cls)
+
+ def init(self):
+ self.conn = self.app.database.get_connection()
+
+ self.cursor = self.conn.cursor(cursor_factory=UpdateCursor)
+ self.cursor.stats = self.stats
+
+ def enqueue(self, update):
+ self.updates.put(update)
+
+ self.stats.enqueued += 1
+
+ def run(self):
+ while True:
+ if self.stop_requested:
+ break
+
+ try:
+ update = self.updates.get(True, 1)
+ except Empty:
+ continue
+
+ self.stats.dequeued += 1
+
+ update.process(self)
+
+class UpdateStats(object):
+
+ def __init__(self, app):
+ self.enqueued = 0
+ self.dequeued = 0
+ self.dropped = 0
+
+ self.objects_created = 0
+ self.objects_updated = 0
+ self.objects_deleted = 0
+
+ self.objects_created_by_class = defaultdict(int)
+ self.objects_updated_by_class = defaultdict(int)
+ self.objects_deleted_by_class = defaultdict(int)
+
+ self.sql_ops = 0
+ self.errors = 0
+
+ self.time = None
+ self.cpu = 0
+ self.memory = 0
+
+class UpdateCursor(Cursor):
+ def execute(self, sql, args=None):
+ super(UpdateCursor, self).execute(sql, args)
+
+ self.stats.sql_ops += 1
+
+class Update(object):
+ def __init__(self, model):
+ self.model = model
+
+ def process(self, thread):
+ log.debug("Processing %s", self)
+ try:
+ self.do_process(thread.cursor, thread.stats, thread.app.packages)
+ thread.conn.commit()
+ except UpdateDropped:
+ log.debug("Update dropped")
+
+ thread.conn.rollback()
+
+ thread.stats.dropped += 1
+ except:
+ log.debug("Update failed", exc_info=True)
+
+ thread.conn.rollback()
+
+ thread.stats.errors += 1
+
+ if thread.halt_on_error:
+ raise
+
+ def do_process(self, cursor, stats, packages):
+ raise Exception("Not implemented")
+
+ def __repr__(self):
+ return self.__class__.__name__
+
+class ObjectUpdate(Update):
+ def __init__(self, model, plumage_object):
+ super(ObjectUpdate, self).__init__(model)
+
+ self.plumage_object = plumage_object
+
+ def do_process(self, cursor, stats, bound_classes, bound_packages):
+ cls = self.get_class()
+ object_id = self.get_object_id()
+
+ # Okay, we want to do a lookup by object id here.
+ # If we can't find it, we create it. Agent is
+ # a mint Agent class.
+ # We need a lookup by field on machine.
+
+ try:
+ obj = agent.get_object( cursor, cls, object_id)
+ except RosemaryNotFound:
+ obj = self.create_object(cursor, stats, cls)
+ return
+
+ self.update_object(cursor, stats, obj)
+
+ def maybe_drop_sample(self, obj):
+ properties = self.qmf_object.getProperties()
+ statistics = self.qmf_object.getStatistics()
+
+ if not properties and statistics:
+ # Just stats; do we want it?
+ # if stats.enqueued - stats.dequeued > 500:
+
+ now = time.time()
+ update = self.qmf_object.getTimestamps()[0] / 1000000000
+ sample = obj._sample_time
+
+ if update < now - sample_window_max:
+ # The sample is too old
+ raise UpdateDropped()
+
+ if sample and sample > now - sample_window_min:
+ # The samples are too fidelitous
+ raise UpdateDropped()
+
+ def create_object(self, cursor, stats, cls):
+ obj = cls.create_object(cursor)
+
+ object_columns = list()
+ sample_columns = list()
+
+ table = cls.sql_table
+
+ object_columns.append(table._id)
+
+ self.process_properties(obj, object_columns, cursor)
+ self.process_statistics(obj, object_columns, sample_columns)
+
+ statements = list()
+
+ sql = cls.sql_insert_object.emit(object_columns)
+ statements.append(sql)
+
+ if sample_columns:
+ sql = cls.sql_samples_insert.emit(sample_columns)
+ statements.append(sql)
+ obj._sample_time = time.time()
+
+ sql = "; ".join(statements)
+ self.execute_sql(cursor, sql, obj.__dict__)
+ obj._save_time = datetime.now()
+ self.model.print_event(3, "Created %s", obj)
+
+ stats.objects_created += 1
+ #stats.objects_created_by_class[cls] += 1
+
+ return obj
+
+ def update_object(self, cursor, stats, obj):
+ object_columns = list()
+ sample_columns = list()
+
+ self.process_properties(obj, object_columns, cursor)
+ self.process_statistics(obj, object_columns, sample_columns)
+
+ statements = list()
+ cls = obj._class
+
+ # force a write if it's been too long, even if the values match
+ if object_columns:
+ sql = cls.sql_update_object.emit(object_columns)
+ statements.append(sql)
+
+ if sample_columns:
+ sql = cls.sql_samples_insert.emit(sample_columns)
+ statements.append(sql)
+
+ obj._sample_time = time.time()
+
+ if not statements:
+ raise UpdateDropped()
+
+ sql = "; ".join(statements)
+ self.execute_sql(cursor, sql, obj.__dict__)
+
+ self.model.print_event(4, "Updated %s", obj)
+
+ stats.objects_updated += 1
+ #stats.objects_updated_by_class[cls] += 1
+
+ def process_properties(self, obj, columns, cursor):
+ cls = obj._class
+
+ # getProperties comes from console.py
+ # list of tuples, first is an instance
+ # which can be spoofed, second is a value for the property
+
+ for prop, value in self.qmf_object.getProperties():
+ try:
+ col, nvalue = self.process_value(cls, prop, value)
+ except MappingException, e:
+ log.debug(e)
+ continue
+
+ # XXX This optimization will be obsolete when QMF does it
+ # instead
+ if nvalue == getattr(obj, col.name):
+ continue
+
+ setattr(obj, col.name, nvalue)
+ columns.append(col)
+
+ def process_value(self, cls, prop, value):
+ try:
+ col = cls._properties_by_name[prop.name].sql_column
+ except KeyError:
+ raise MappingException("Property %s is unknown" % prop)
+
+ if value is not None:
+ value = transform_value(prop, value)
+
+ return col, value
+
+ def process_statistics(self, obj, update_columns, insert_columns):
+ build_columns = list()
+ saw_change = False
+
+
+ # getStatistics comes from console.py
+ # list of tuples, first is an instance
+ # which can be spoofed, second is a value for the property
+
+ for stat, value in self.qmf_object.getStatistics():
+ try:
+ col = obj._class._statistics_by_name[stat.name].sql_column
+ except KeyError:
+ log.debug("Statistic %s is unknown", stat)
+
+ continue
+
+ if value is not None:
+ value = transform_value(stat, value)
+
+ # Don't write unchanged values
+ #
+ # XXX This optimization will be obsolete when QMF does it
+ # instead
+ if value != getattr(obj, col.name):
+ setattr(obj, col.name, value)
+ update_columns.append(col)
+ saw_change = True
+
+ # If we do end up seeing a value change, we will
+ # need to insert an entire row so build it up
+ build_columns.append(col)
+
+ if saw_change:
+ insert_columns.extend(build_columns)
+
+ def execute_sql(self, cursor, text, args):
+ try:
+ cursor.execute(text, args)
+ except:
+ log.debug("%s failed sql execute", self, exc_info=True)
+ log.error("Sql execute failed")
+ log.error("Sql text: %s", text)
+ log.error("Sql values:")
+
+ for item in sorted(args.items()):
+ log.error(" %-34s %r", *item)
+
+ log.error("Sql row count: %i", cursor.rowcount)
+
+ log.error("object properties:")
+
+ # see process_properties
+ for item in sorted(self.qmf_object.getProperties()):
+ log.error(" %-34s %r", *item)
+
+ log.error("object statistics:")
+
+ # see process statistics
+ for item in sorted(self.qmf_object.getStatistics()):
+ log.error(" %-34s %r", *item)
+
+ raise
+
+ def __repr__(self):
+ name = self.__class__.__name__
+ return name
+
+ #agent_id = self.get_agent_id()
+ #cls = self.qmf_object.getClassKey().getClassName()
+ #obj_id = self.get_object_id()
+
+ #return "%s(%s,%s,%s)" % (name, agent_id, cls, obj_id)
+
+class MappingException(Exception):
+ pass
+
+def transform_default(value):
+ return value
+
+def transform_timestamp(value):
+ if value != 0:
+ return datetime.fromtimestamp(value / 1000000000)
+
+def transform_pickle(value):
+ return pickle.dumps(x)
+
+transformers = list([transform_default for x in range(32)])
+
+transformers[8] = transform_timestamp
+transformers[10] = str
+transformers[14] = str
+transformers[15] = transform_pickle
+
+def transform_value(attr, value):
+ return transformers[attr.type](value)
Modified: branches/play_plumage/rosemary/python/rosemary/model.py
===================================================================
--- branches/play_plumage/rosemary/python/rosemary/model.py 2012-03-30 17:17:00 UTC (rev 5279)
+++ branches/play_plumage/rosemary/python/rosemary/model.py 2012-03-30 20:27:05 UTC (rev 5280)
@@ -16,25 +16,29 @@
self.sql_logging_enabled = False
- def load_model_dir(self, path):
- assert os.path.isdir(path)
+ def load_model_dir(self, paths):
+ # Let this work across multiple directories
+ if not type(paths) in (list, tuple):
+ paths = [paths]
- extensions = os.path.join(path, "rosemary.xml")
+ for path in paths:
+ assert os.path.isdir(path)
+ extensions = os.path.join(path, "rosemary.xml")
- for name in os.listdir(path):
- file_path = os.path.join(path, name)
+ for name in os.listdir(path):
+ file_path = os.path.join(path, name)
- if not os.path.isfile(file_path):
- continue
+ if not os.path.isfile(file_path):
+ continue
- if file_path == extensions:
- continue
+ if file_path == extensions:
+ continue
- if file_path.endswith(".xml"):
- self.load_model_file(file_path)
+ if file_path.endswith(".xml"):
+ self.load_model_file(file_path)
- if os.path.isfile(extensions):
- self.load_extensions(extensions)
+ if os.path.isfile(extensions):
+ self.load_extensions(extensions)
def load_model_file(self, path):
tree = ElementTree()
12 years
r5279 - trunk/cumin/etc
by tmckay@fedoraproject.org
Author: tmckay
Date: 2012-03-30 17:17:00 +0000 (Fri, 30 Mar 2012)
New Revision: 5279
Modified:
trunk/cumin/etc/module.profile
Log:
Fix module.profile to point to bin/test for test scripts
Modified: trunk/cumin/etc/module.profile
===================================================================
--- trunk/cumin/etc/module.profile 2012-03-29 18:59:38 UTC (rev 5278)
+++ trunk/cumin/etc/module.profile 2012-03-30 17:17:00 UTC (rev 5279)
@@ -1,3 +1,3 @@
export PYTHONPATH="${PWD}/python:${PYTHONPATH}"
-export PATH="${PWD}/bin:${PATH}"
+export PATH="${PWD}/bin:${PWD}/bin/test:${PATH}"
export CUMIN_HOME="${PWD}/instance"
12 years
r5278 - trunk/cumin/bin
by tmckay@fedoraproject.org
Author: tmckay
Date: 2012-03-29 18:59:38 +0000 (Thu, 29 Mar 2012)
New Revision: 5278
Modified:
trunk/cumin/bin/cumin-admin
Log:
Fix exception on missing user or role for remove-assignment
Merged revision 5265 from roles branch
Modified: trunk/cumin/bin/cumin-admin
===================================================================
--- trunk/cumin/bin/cumin-admin 2012-03-29 18:52:47 UTC (rev 5277)
+++ trunk/cumin/bin/cumin-admin 2012-03-29 18:59:38 UTC (rev 5278)
@@ -567,6 +567,11 @@
user = app.admin.get_user(cursor, user_name)
role = app.admin.get_role(cursor, role_name)
+ if not user:
+ error("Specified user %s does not exist" % user_name)
+ if not role:
+ error("Specified role %s does not exist" % role_name)
+
return user, role
def handle_change_password(app, cursor, opts, args):
12 years
r5277 - in trunk: cumin/python/cumin/grid wooly/python/wooly
by tmckay@fedoraproject.org
Author: tmckay
Date: 2012-03-29 18:52:47 +0000 (Thu, 29 Mar 2012)
New Revision: 5277
Modified:
trunk/cumin/python/cumin/grid/job.py
trunk/cumin/python/cumin/grid/submission.py
trunk/wooly/python/wooly/forms.py
Log:
Screen 'Reason' dialogs for double quotes and XML
BZ807912
Modified: trunk/cumin/python/cumin/grid/job.py
===================================================================
--- trunk/cumin/python/cumin/grid/job.py 2012-03-29 18:51:14 UTC (rev 5276)
+++ trunk/cumin/python/cumin/grid/job.py 2012-03-29 18:52:47 UTC (rev 5277)
@@ -16,7 +16,7 @@
from wooly import Widget, Parameter, Attribute
from wooly.util import StringCatalog, Writer, escape_amp, escape_entity,\
xml_escape
-from wooly.forms import Form, FormButton, StringField
+from wooly.forms import Form, FormButton, StringField, NoXMLStringField
from wooly.widgets import ModeSet, PropertySet, TemplateRenderer, Notice
from wooly.template import WidgetTemplate
from wooly.parameters import ListParameter, IntegerParameter, DictParameter
@@ -1137,7 +1137,7 @@
self.task.invoke(session, scheduler, job_id, reason, submission)
self.task.exit_with_redirect(session)
-class ReasonField(StringField):
+class ReasonField(NoXMLStringField):
def render_title(self, session):
return "Reason"
Modified: trunk/cumin/python/cumin/grid/submission.py
===================================================================
--- trunk/cumin/python/cumin/grid/submission.py 2012-03-29 18:51:14 UTC (rev 5276)
+++ trunk/cumin/python/cumin/grid/submission.py 2012-03-29 18:52:47 UTC (rev 5277)
@@ -18,7 +18,7 @@
from wooly import Attribute, Parameter
from wooly.forms import StringField, ScalarField, FormError, OptionInputSet,\
- MultilineStringField, FormField, IntegerField, LabelFormField
+ MultilineStringField, FormField, IntegerField, LabelFormField, NoXMLStringField
from wooly.parameters import IntegerParameter
log = logging.getLogger("cumin.grid.submission")
@@ -220,7 +220,7 @@
self.columns.append(scheduler._id.sql_column)
self.columns.append(scheduler.Name.sql_column)
-class JobDescriptionField(StringField):
+class JobDescriptionField(NoXMLStringField):
def __init__(self, app, name):
super(JobDescriptionField, self).__init__(app, name)
@@ -233,18 +233,6 @@
def render_help(self, session):
return "This text will identify the submission"
- def validate(self, session):
- super(JobDescriptionField, self).validate(session)
-
- des = self.get(session)
- if '"' in des:
- error = FormError("Double quotes are not allowed in submission descriptions")
- self.form.errors.add(session, error)
-
- elif xml_escape(des) != des:
- error = FormError("XML special characters are not allowed in submission descriptions")
- self.form.errors.add(session, error)
-
class JobSchedulerField(ScalarField):
def __init__(self, app, name):
super(JobSchedulerField, self).__init__(app, name, None)
Modified: trunk/wooly/python/wooly/forms.py
===================================================================
--- trunk/wooly/python/wooly/forms.py 2012-03-29 18:51:14 UTC (rev 5276)
+++ trunk/wooly/python/wooly/forms.py 2012-03-29 18:52:47 UTC (rev 5277)
@@ -133,6 +133,25 @@
title = self.widget.render_title(session)
return "The '%s' field must have a value" % title
+class QuoteValueError(FormError):
+ def __init__(self, widget):
+ super(QuoteValueError, self).__init__(None)
+
+ self.widget = widget
+
+ def get_message(self, session):
+ title = self.widget.render_title(session)
+ return "The '%s' field may not contain double quotes" % title
+
+class XMLValueError(FormError):
+ def __init__(self, widget):
+ super(XMLValueError, self).__init__(None)
+
+ self.widget = widget
+
+ def get_message(self, session):
+ title = self.widget.render_title(session)
+ return "The '%s' field may not contain XML special characters" % title
class EmptyInputError(FormError):
def __init__(self):
super(EmptyInputError, self).__init__("This value is required")
@@ -461,6 +480,19 @@
self.input = StringInput(app, "input")
self.add_child(self.input)
+class NoXMLStringField(StringField):
+ def validate(self, session):
+ super(NoXMLStringField, self).validate(session)
+
+ des = self.get(session)
+ if '"' in des:
+ error = QuoteValueError(self)
+ self.form.errors.add(session, error)
+
+ elif xml_escape(des) != des:
+ error = XMLValueError(self)
+ self.form.errors.add(session, error)
+
class MultilineStringField(ScalarField):
def __init__(self, app, name):
super(MultilineStringField, self).__init__(app, name, None)
12 years
r5276 - trunk/cumin/python/cumin
by tmckay@fedoraproject.org
Author: tmckay
Date: 2012-03-29 18:51:14 +0000 (Thu, 29 Mar 2012)
New Revision: 5276
Modified:
trunk/cumin/python/cumin/objectframe.py
Log:
Fix double escape on the Details page
BZ438142 (modification)
Modified: trunk/cumin/python/cumin/objectframe.py
===================================================================
--- trunk/cumin/python/cumin/objectframe.py 2012-03-28 17:54:06 UTC (rev 5275)
+++ trunk/cumin/python/cumin/objectframe.py 2012-03-29 18:51:14 UTC (rev 5276)
@@ -107,7 +107,8 @@
for attr in self.get_attributes(session):
# name and title are from rosemary xml files
name = attr.title
- value = obj.get_formatted_value(attr.name, escape=True)
+ # We are going to escape the value in ObjectAttributesEntry below
+ value = obj.get_formatted_value(attr.name, escape=False)
title = attr.description
writer.write(self.entry.render(session, name, value, title))
12 years
r5275 - in branches/play_plumage: cumin/bin cumin/model cumin/python/cumin rosemary/python/rosemary
by tmckay@fedoraproject.org
Author: tmckay
Date: 2012-03-28 17:54:06 +0000 (Wed, 28 Mar 2012)
New Revision: 5275
Added:
branches/play_plumage/cumin/model/plumage.xml
Modified:
branches/play_plumage/cumin/bin/cumin-admin
branches/play_plumage/cumin/model/rosemary.xml
branches/play_plumage/cumin/python/cumin/main.py
branches/play_plumage/rosemary/python/rosemary/model.py
branches/play_plumage/rosemary/python/rosemary/sqloperation.py
Log:
Fixes to allow xml schemas with qmf_headers="False" for non-qmf classes
Modified: branches/play_plumage/cumin/bin/cumin-admin
===================================================================
--- branches/play_plumage/cumin/bin/cumin-admin 2012-03-27 20:28:39 UTC (rev 5274)
+++ branches/play_plumage/cumin/bin/cumin-admin 2012-03-28 17:54:06 UTC (rev 5275)
@@ -77,7 +77,7 @@
# cumin-admin is the mechanism for fixing the schema so we
# have to avoid the check here!
try:
- app.init(schema_version_check=False)
+ app.db_init(schema_version_check=False)
except OperationalError:
print "Can't talk to the database"
error("Run 'cumin-database check' as root for more information")
Added: branches/play_plumage/cumin/model/plumage.xml
===================================================================
--- branches/play_plumage/cumin/model/plumage.xml (rev 0)
+++ branches/play_plumage/cumin/model/plumage.xml 2012-03-28 17:54:06 UTC (rev 5275)
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<schema package="com.redhat.grid.plumage">
+ <class name="OSUtil" qmf_headers="False">
+ <property name="uuid" index="y" type="uuid" access="RC" desc="UUID of System Image"/>
+
+ <property name="osName" type="sstr" access="RO" desc="Operating System Name" />
+
+ <statistic name="avail" type="uint32" unit="uint32" />
+ <statistic name="used" type="uint32" unit="uint32" />
+ </class>
+</schema>
Modified: branches/play_plumage/cumin/model/rosemary.xml
===================================================================
--- branches/play_plumage/cumin/model/rosemary.xml 2012-03-27 20:28:39 UTC (rev 5274)
+++ branches/play_plumage/cumin/model/rosemary.xml 2012-03-28 17:54:06 UTC (rev 5275)
@@ -546,4 +546,21 @@
</statistic>
</class>
</package>
+
+ <package name="com.redhat.grid.plumage">
+ <class name="OSUtil">
+ <property name="osName">
+ <title>OS</title>
+ </property>
+
+ <statistic name="used">
+ <title>Used</title>
+ </statistic>
+
+ <statistic name="avail">
+ <title>Available</title>
+ </statistic>
+ </class>
+ </package>
+
</model>
Modified: branches/play_plumage/cumin/python/cumin/main.py
===================================================================
--- branches/play_plumage/cumin/python/cumin/main.py 2012-03-27 20:28:39 UTC (rev 5274)
+++ branches/play_plumage/cumin/python/cumin/main.py 2012-03-28 17:54:06 UTC (rev 5275)
@@ -165,6 +165,10 @@
inventory.Module(self, "inventory")
usergrid.Module(self, "usergrid")
+ def db_init(self, schema_version_check=True):
+ self.model.init()
+ self.database.init(schema_version_check)
+
def init(self, schema_version_check=True):
log.info("Initializing %s", self)
Modified: branches/play_plumage/rosemary/python/rosemary/model.py
===================================================================
--- branches/play_plumage/rosemary/python/rosemary/model.py 2012-03-27 20:28:39 UTC (rev 5274)
+++ branches/play_plumage/rosemary/python/rosemary/model.py 2012-03-28 17:54:06 UTC (rev 5275)
@@ -143,7 +143,7 @@
groups_by_name[name] = child
for child in elem.findall("class"):
- cls = RosemaryClass(self, child.get("name"))
+ cls = RosemaryClass(self, child.get("name"), child.get("qmf_headers"))
cls.load(child, groups_by_name)
def extend(self, elem):
@@ -168,7 +168,7 @@
return "%s(%s)" % args
class RosemaryClass(object):
- def __init__(self, package, name):
+ def __init__(self, package, name, qmf_headers):
self._package = package
self._name = name
@@ -213,7 +213,9 @@
self._id = RosemaryAttribute(self, "_id")
- self.add_headers()
+ self.qmf_headers = qmf_headers is None or qmf_headers.lower() == "true"
+ if self.qmf_headers:
+ self.add_headers()
def add_headers(self):
name = "_qmf_agent_id"
@@ -355,15 +357,18 @@
SqlPrimaryKeyConstraint(self.sql_table, name, (id_col,))
def add_sql_constraints(self):
- name = "%s_qmf_id_uq" % self._name
- cols = (self._qmf_agent_id.sql_column, self._qmf_object_id.sql_column)
- SqlUniqueConstraint(self.sql_table, name, cols)
+ if self.qmf_headers:
+ name = "%s_qmf_id_uq" % self._name
+ cols = (self._qmf_agent_id.sql_column, self._qmf_object_id.sql_column)
+ SqlUniqueConstraint(self.sql_table, name, cols)
def add_sql_operations(self):
self.sql_get_new_id = SqlGetNewId(self.sql_table, self.sql_sequence)
self.sql_select_by_id = SqlSelectObject(self.sql_table)
- self.sql_select_by_qmf_id = SqlSelectObjectByQmfId(self.sql_table)
+ if self.qmf_headers:
+ self.sql_select_by_qmf_id = SqlSelectObjectByQmfId(self.sql_table)
+
self.sql_insert_object = SqlInsertObject(self.sql_table)
self.sql_update_object = SqlUpdateObject(self.sql_table)
self.sql_delete_object = SqlDeleteObject(self.sql_table)
@@ -374,16 +379,19 @@
self.sql_samples_table = table
- agent_col = SqlColumn(table, "_qmf_agent_id", sql_text)
- object_col = SqlColumn(table, "_qmf_object_id", sql_text)
+ if self.qmf_headers:
+ agent_col = SqlColumn(table, "_qmf_agent_id", sql_text)
+ object_col = SqlColumn(table, "_qmf_object_id", sql_text)
- name = "%s_qmf_id_idx" % table._name
- SqlIndex(self._package.sql_schema, name, (agent_col, object_col))
+ name = "%s_qmf_id_idx" % table._name
+ SqlIndex(self._package.sql_schema, name, (agent_col, object_col))
- SqlColumn(table, "_qmf_update_time", sql_timestamp)
+ SqlColumn(table, "_qmf_update_time", sql_timestamp)
- self.sql_samples_insert = SqlInsertObjectSamples(table)
- self.sql_samples_delete = SqlDeleteObjectSamples(table)
+ self.sql_samples_insert = SqlInsertObjectSamples(table, self.qmf_headers)
+ if self.qmf_headers:
+ # We will need another way to delete non-qmf samples
+ self.sql_samples_delete = SqlDeleteObjectSamples(table)
def get_object(self, cursor, **criteria):
sql = SqlSelect(self.sql_table)
@@ -457,12 +465,11 @@
return obj
def get_object_by_qmf_id(self, cursor, agent_id, object_id):
+ assert self.qmf_headers
obj = RosemaryObject(self, None)
obj._qmf_agent_id = agent_id
obj._qmf_object_id = object_id
-
self.load_object_by_qmf_id(cursor, obj)
-
return obj
def get_new_id(self, cursor):
@@ -494,6 +501,7 @@
def load_object_by_qmf_id(self, cursor, obj):
assert isinstance(obj, RosemaryObject)
+ assert self.qmf_headers
assert obj._qmf_agent_id, obj
assert obj._qmf_object_id, obj
@@ -600,6 +608,14 @@
self.short_title = elem.findtext("short")
self.unique = elem.get("unique", "n") == "y" and True
formatter = elem.findtext("formatter")
+
+ # Allow overloading of optional in the extensions
+ # This is nice, because sometimes we have to mark
+ # items as optional for backwards compatibility
+ optional = elem.get("optional")
+ if optional is not None:
+ self.optional = optional == "y"
+
if formatter:
meth = getattr(util, formatter, None)
@@ -711,7 +727,7 @@
type = sql_types_by_qmf_type_string[self.type]
self.sql_column = SqlColumn(self.cls.sql_table, self.name, type)
- self.sql_column.nullable = True
+ self.sql_column.nullable = self.optional
col = SqlColumn(self.cls.sql_samples_table, self.name, type)
col.nullable = self.optional
Modified: branches/play_plumage/rosemary/python/rosemary/sqloperation.py
===================================================================
--- branches/play_plumage/rosemary/python/rosemary/sqloperation.py 2012-03-27 20:28:39 UTC (rev 5274)
+++ branches/play_plumage/rosemary/python/rosemary/sqloperation.py 2012-03-28 17:54:06 UTC (rev 5275)
@@ -83,7 +83,6 @@
class SqlSelectObjectByQmfId(SqlSelect):
def __init__(self, table):
super(SqlSelectObjectByQmfId, self).__init__(table)
-
self.add_filter(SqlValueFilter(self.table._qmf_agent_id))
self.add_filter(SqlValueFilter(self.table._qmf_object_id))
@@ -97,6 +96,11 @@
return "insert into %s (%s) values (%s)" % (table, cols, vals)
class SqlInsertObjectSamples(SqlOperation):
+ def __init__(self, table, qmf_headers):
+ super(SqlInsertObjectSamples, self).__init__(table)
+
+ self.qmf_headers = qmf_headers
+
def emit(self, columns, options=None):
table = getattr(self.table, "identifier", self.table)
names = [x.name for x in columns]
@@ -104,11 +108,12 @@
cols = ["\"%s\"" % x for x in names]
vals = ["%%(%s)s" % x for x in names]
- cols.append("\"_qmf_agent_id\"")
- cols.append("\"_qmf_object_id\"")
+ if self.qmf_headers:
+ cols.append("\"_qmf_agent_id\"")
+ cols.append("\"_qmf_object_id\"")
- vals.append("%(_qmf_agent_id)s")
- vals.append("%(_qmf_object_id)s")
+ vals.append("%(_qmf_agent_id)s")
+ vals.append("%(_qmf_object_id)s")
cols = ", ".join(cols)
vals = ", ".join(vals)
12 years
r5274 - in branches/play_plumage/cumin: bin python/cumin python/cumin/account python/cumin/grid python/cumin/inventory python/cumin/messaging python/cumin/usergrid
by tmckay@fedoraproject.org
Author: tmckay
Date: 2012-03-27 20:28:39 +0000 (Tue, 27 Mar 2012)
New Revision: 5274
Modified:
branches/play_plumage/cumin/bin/cumin-admin
branches/play_plumage/cumin/bin/cumin-web
branches/play_plumage/cumin/python/cumin/__init__.py
branches/play_plumage/cumin/python/cumin/account/main.py
branches/play_plumage/cumin/python/cumin/grid/main.py
branches/play_plumage/cumin/python/cumin/inventory/main.py
branches/play_plumage/cumin/python/cumin/messaging/main.py
branches/play_plumage/cumin/python/cumin/usergrid/main.py
Log:
Remove circular dependencies for rosemary_model caused by import in cumin/__init__.py
Modified: branches/play_plumage/cumin/bin/cumin-admin
===================================================================
--- branches/play_plumage/cumin/bin/cumin-admin 2012-03-25 20:56:51 UTC (rev 5273)
+++ branches/play_plumage/cumin/bin/cumin-admin 2012-03-27 20:28:39 UTC (rev 5274)
@@ -13,7 +13,7 @@
from parsley.collectionsex import defaultdict
-from cumin import *
+from cumin.main import *
from cumin.config import *
from cumin.util import *
from cumin.admin import SchemaMissing
Modified: branches/play_plumage/cumin/bin/cumin-web
===================================================================
--- branches/play_plumage/cumin/bin/cumin-web 2012-03-25 20:56:51 UTC (rev 5273)
+++ branches/play_plumage/cumin/bin/cumin-web 2012-03-27 20:28:39 UTC (rev 5274)
@@ -1,11 +1,12 @@
#!/usr/bin/python
import os
import sys
+import traceback
home = os.environ.get("CUMIN_HOME", os.path.normpath("/usr/share/cumin"))
sys.path.append(os.path.join(home, "python"))
-from cumin import *
+from cumin.main import *
from cumin.config import *
from cumin.util import *
from parsley.loggingex import PipeLogThread
@@ -82,7 +83,7 @@
sys.stdout = os.fdopen(out_w, "w", 0)
except:
restore_IO()
- print_exc()
+ traceback.print_exc()
pipeThread = None
# Use ArgError to jump to the finally block and exit
@@ -197,7 +198,7 @@
return_code = CuminErrors.SCHEMA_VER_ERROR
except:
- print_exc()
+ traceback.print_exc()
return_code = CuminErrors.UNHANDLED_ERROR
if cumin:
Modified: branches/play_plumage/cumin/python/cumin/__init__.py
===================================================================
--- branches/play_plumage/cumin/python/cumin/__init__.py 2012-03-25 20:56:51 UTC (rev 5273)
+++ branches/play_plumage/cumin/python/cumin/__init__.py 2012-03-27 20:28:39 UTC (rev 5274)
@@ -1 +1,5 @@
-from main import *
+# Doing this here is a problem, since subpieces of cumin like cumin.util or cumin.formats are
+# widely used in other modules like mint or rosemary. This causes everything to be touched
+# when cumin.x is referenced, and it causes circular dependencies.
+
+#from main import *
Modified: branches/play_plumage/cumin/python/cumin/account/main.py
===================================================================
--- branches/play_plumage/cumin/python/cumin/account/main.py 2012-03-25 20:56:51 UTC (rev 5273)
+++ branches/play_plumage/cumin/python/cumin/account/main.py 2012-03-27 20:28:39 UTC (rev 5274)
@@ -1,8 +1,6 @@
-from cumin import *
-from cumin.util import *
+from cumin.main import CuminModule
+from widgets import LoginPage, AccountPage
-from widgets import *
-
class Module(CuminModule):
def __init__(self, app, name):
super(Module, self).__init__(app, name)
Modified: branches/play_plumage/cumin/python/cumin/grid/main.py
===================================================================
--- branches/play_plumage/cumin/python/cumin/grid/main.py 2012-03-25 20:56:51 UTC (rev 5273)
+++ branches/play_plumage/cumin/python/cumin/grid/main.py 2012-03-27 20:28:39 UTC (rev 5274)
@@ -2,7 +2,7 @@
from wooly.widgets import *
from wooly.resources import *
-from cumin import *
+from cumin.main import CuminModule
from cumin.objecttask import *
from cumin.util import *
Modified: branches/play_plumage/cumin/python/cumin/inventory/main.py
===================================================================
--- branches/play_plumage/cumin/python/cumin/inventory/main.py 2012-03-25 20:56:51 UTC (rev 5273)
+++ branches/play_plumage/cumin/python/cumin/inventory/main.py 2012-03-27 20:28:39 UTC (rev 5274)
@@ -2,7 +2,7 @@
from wooly.widgets import *
from wooly.resources import *
-from cumin import *
+from cumin.main import CuminModule
from cumin.widgets import *
from cumin.util import *
Modified: branches/play_plumage/cumin/python/cumin/messaging/main.py
===================================================================
--- branches/play_plumage/cumin/python/cumin/messaging/main.py 2012-03-25 20:56:51 UTC (rev 5273)
+++ branches/play_plumage/cumin/python/cumin/messaging/main.py 2012-03-27 20:28:39 UTC (rev 5274)
@@ -2,7 +2,7 @@
from wooly.widgets import *
from wooly.resources import *
-from cumin import *
+from cumin.main import CuminModule
from cumin.util import *
from broker import *
Modified: branches/play_plumage/cumin/python/cumin/usergrid/main.py
===================================================================
--- branches/play_plumage/cumin/python/cumin/usergrid/main.py 2012-03-25 20:56:51 UTC (rev 5273)
+++ branches/play_plumage/cumin/python/cumin/usergrid/main.py 2012-03-27 20:28:39 UTC (rev 5274)
@@ -1,4 +1,4 @@
-from cumin import *
+from cumin.main import CuminModule
from cumin.util import *
from widgets import *
12 years
r5273 - branches/roles_II/cumin/model/access
by tmckay@fedoraproject.org
Author: tmckay
Date: 2012-03-25 20:56:51 +0000 (Sun, 25 Mar 2012)
New Revision: 5273
Added:
branches/roles_II/cumin/model/access/persona.xml
Log:
Forgot to add the persona definitions
Added: branches/roles_II/cumin/model/access/persona.xml
===================================================================
--- branches/roles_II/cumin/model/access/persona.xml (rev 0)
+++ branches/roles_II/cumin/model/access/persona.xml 2012-03-25 20:56:51 UTC (rev 5273)
@@ -0,0 +1,54 @@
+<PersonaMap>
+ <Persona name="default" auth="True">
+ <Module name="account"/>
+ <Module name="configuration"/>
+ <Module name="grid"/>
+ <Module name="inventory"/>
+ <Module name="messaging"/>
+ <Module name="usergrid"/>
+
+ <GroupAccess name="nogroup">
+ <MainPage name="login.html"/>
+ </GroupAccess>
+
+ <GroupAccess name="user">
+ <MainPage name="usergrid.html"/>
+ <ModuleAccess name="account"/>
+ <ModuleAccess name="usergrid"/>
+ </GroupAccess>
+
+ <GroupAccess name="admin">
+ <MainPage name="index.html"/>
+ <ModuleAccess name="*"/>
+ </GroupAccess>
+ </Persona>
+
+ <Persona name="grid" auth="True">
+ <Module name="account"/>
+ <Module name="configuration"/>
+ <Module name="grid"/>
+ <Module name="inventory"/>
+ <Module name="usergrid"/>
+
+ <GroupAccess name="nogroup">
+ <MainPage name="login.html"/>
+ </GroupAccess>
+
+ <GroupAccess name="user">
+ <MainPage name="usergrid.html"/>
+ <ModuleAccess name="account"/>
+ <ModuleAccess name="usergrid"/>
+ </GroupAccess>
+
+ <GroupAccess name="admin">
+ <MainPage name="index.html"/>
+ <ModuleAccess name="*"/>
+ </GroupAccess>
+ </Persona>
+
+ <Persona name="messaging" auth="False">
+ <Module name="account"/>
+ <Module name="inventory"/>
+ <Module name="messaging"/>
+ </Persona>
+</PersonaMap>
\ No newline at end of file
12 years, 1 month
r5272 - in branches/roles_II: cumin/python/cumin cumin/python/cumin/grid cumin/python/cumin/inventory cumin/python/cumin/messaging cumin/python/cumin/usergrid wooly/python/wooly
by tmckay@fedoraproject.org
Author: tmckay
Date: 2012-03-25 20:24:08 +0000 (Sun, 25 Mar 2012)
New Revision: 5272
Added:
branches/roles_II/cumin/python/cumin/persona.py
Removed:
branches/roles_II/cumin/python/cumin/authorize.py
Modified:
branches/roles_II/cumin/python/cumin/grid/main.py
branches/roles_II/cumin/python/cumin/grid/pool.py
branches/roles_II/cumin/python/cumin/inventory/main.py
branches/roles_II/cumin/python/cumin/inventory/system.py
branches/roles_II/cumin/python/cumin/main.py
branches/roles_II/cumin/python/cumin/messaging/main.py
branches/roles_II/cumin/python/cumin/usergrid/main.py
branches/roles_II/cumin/python/cumin/widgets.py
branches/roles_II/wooly/python/wooly/pages.py
branches/roles_II/wooly/python/wooly/table.py
branches/roles_II/wooly/python/wooly/widgets.py
Log:
Try out an alternative approach to role enforcement with logical modules:
* Uses logical modules to group widgets. Any widget may be part of any module simply by
setting self.cumin_module = "module_name". Widgets that do not have self.cumin_module set do not
belong to any module and therefore are authorized for all users. Self.cumin_module may be a list.
* Combines the concepts of persona and authorization into a single solution based around
modules and defined in xml. Persona ("default", "messaging", "grid") was originally created
to control content and presentation across the whole application. Authorization specifies what
subset of that content is available from a particular account. A "persona" now defines which
modules are loaded, which authorization groups are valid for the persona, and which modules
each group is authorized to interact with. Personas are now also freely definable, whereas
the original three were hardcoded. Backwards compatibility is maintained.
* The authorization burden should be light, since only a handful of widgets have self.cumin_module
set to a value (all others will take an early out and the authorize_cb calls will be trivial).
Since Cumin processes widgets hierarchically, it is only necessary to authorize certain types of widgets;
in general, these are top level frames and HtmlPages. We also have the flexibility to scope
functionality arbitrarily anywhere within a hierarchy by associating subwidgets with particular modules
to control their procesing. The configuration data associated with Wallaby is an example of this --
certain Inventory table columns have self.cumin_module set to "configuration" so those columns can be
dropped by turning off the loading of the abstract "configuration" module.
* In addition to the authorize_cb calls during process() and render() for all top level widgets, a few
more calls are necessary to cover authorization everywhere. Tab sets, page link sets, and table header/row
widgets (generally, any containers that point to other widgets) must call authorize_cb on the widgets
they reference to make sure unauthorized widgets are not drawn. Adding the authorize_cb calls here keep
these indirect render/process calls from being missed.
Deleted: branches/roles_II/cumin/python/cumin/authorize.py
===================================================================
--- branches/roles_II/cumin/python/cumin/authorize.py 2012-03-25 19:57:53 UTC (rev 5271)
+++ branches/roles_II/cumin/python/cumin/authorize.py 2012-03-25 20:24:08 UTC (rev 5272)
@@ -1,145 +0,0 @@
-#!/usr/bin/env python
-import logging
-import os.path
-import re
-
-try:
- import xml.etree.ElementTree as etree
-except ImportError:
- import elementtree.ElementTree as etree
-
-log = logging.getLogger("cumin.authorize")
-
-class CuminAuthorizeMap(object):
-
- def __init__(self):
- log.info("Initializing %s", self.__class__.__name__)
- regs = []
- self.mapping = {}
- self.fallbacks = {}
- self.filepath = None
-
- def __repr__(self):
- return ("%s %s" % ( self.__class__.__name__, self.filepath ))
-
- def parse_accessfile(self, filepath):
- #TODO: handle exceptions during parsing
- acctree = etree.ElementTree().parse(filepath)
- merges = {}
- for gacc in acctree.getiterator('GroupAccess'):
- gkey = gacc.attrib["name"]
- self.mapping[gkey] = []
- self.fallbacks[gkey] = "index.html"
- log.debug("Adding group element %s" , gkey)
- for child in gacc.getchildren():
- if child.tag == "WidgetAccess":
- wa = child.attrib['reg']
- self.mapping[gkey].append(re.compile(wa))
- log.debug("Adding widget access %s for %s", wa, gkey)
- elif child.tag == "SubGroupAccess":
- merges[gkey] = child.attrib["name"]
- elif child.tag == "FallbackPage":
- self.fallbacks[gkey] = child.attrib["name"]
- else:
- log.error("Illegal access tag %s in tree", child.tag)
- #TODO: handle adding properly
- for k in merges.iterkeys():
- self.mapping[k].extend(self.mapping[merges[k]])
-
- def lookup(self,group,widget):
- try:
- for w in self.mapping[group]:
- if w.match(widget):
- return True
- except KeyError:
- return False
- return False
-
- def find_fallback(self, group):
- try:
- return self.fallbacks[group]
- except KeyError:
- return None
-
- def map_is_empty(self):
- return len(self.mapping) == 0
-
-class CuminAuthorizator(object):
- def __init__(self, app, access_path):
- self.app = app
- self.access_path = access_path
- log.info("Initializing %s", self)
- self.accmap = CuminAuthorizeMap()
- modules = app.modules
-
- if access_path is not None:
- log.debug("Access file path is %s", access_path)
- if os.path.isdir(access_path):
- files = [os.path.join(access_path, x) \
- for x in os.listdir(access_path)]
- elif os.path.isfile(access_path):
- files = [access_path]
- else:
- files = []
- log.error("Path '%s' for access files does not exist!" % access_path)
-
- for accfile in files:
- if os.path.isfile(accfile) and \
- os.path.splitext(accfile)[1] == ".xml":
- try:
- self.accmap.parse_accessfile(accfile)
- except:
- log.error("Access file '%s' does not parse!" % accfile)
- log.info("MODULES %s", modules)
-
- def is_enforcing(self):
- return self.access_path is not None
-
- def map_is_empty(self):
- return self.accmap.map_is_empty()
-
- def find_fallback(self, web_session):
- # Find a fallback page for the current login session.
- # If the user is part of multiple groups, just pick the
- # first one. There may be a way to make a priority scheme here,
- # but does it really matter?
- try:
- group = web_session.client_session.attributes['login_session'].group
- except KeyError:
- group = "nogroup"
- if type(group) == type([]):
- group = group[0]
- return self.accmap.find_fallback(group)
-
- def contains_valid_group(self, groups):
- for g in groups:
- if g in self.accmap.mapping:
- return True
- return False
-
- def authorize(self, web_session, widget):
- if not self.is_enforcing(): # or not widget.do_authorize:
- # The feature is disabled, everything is allowed
- return True
- try:
- group = web_session.client_session.attributes['login_session'].group
- except KeyError:
- group = "nogroup"
- pass
-
- #TODO: bleee ugly ugly ... -> CuminGenericWidget ? .
- # skip wooly widgets ....
- if widget.my_name.startswith("wooly"):
- return True
- if type(group) == type([]):
- for g in group:
- if self.accmap.lookup(g, widget.my_name):
- log.debug("Allowing %s authorization for %s ",
- widget.my_name, group)
- return True
- else:
- return self.accmap.lookup(group,widget.my_name)
-
- log.debug("Denying %s authorization for %s ", widget.my_name, group)
- return False
-
Modified: branches/roles_II/cumin/python/cumin/grid/main.py
===================================================================
--- branches/roles_II/cumin/python/cumin/grid/main.py 2012-03-25 19:57:53 UTC (rev 5271)
+++ branches/roles_II/cumin/python/cumin/grid/main.py 2012-03-25 20:24:08 UTC (rev 5272)
@@ -26,6 +26,8 @@
super(Module, self).init()
self.frame = PoolFrame(self.app, "grid")
+ self.frame.cumin_module = self.name
+
self.app.main_page.main.grid = self.frame
self.app.main_page.main.add_tab(self.frame)
Modified: branches/roles_II/cumin/python/cumin/grid/pool.py
===================================================================
--- branches/roles_II/cumin/python/cumin/grid/pool.py 2012-03-25 19:57:53 UTC (rev 5271)
+++ branches/roles_II/cumin/python/cumin/grid/pool.py 2012-03-25 20:24:08 UTC (rev 5272)
@@ -78,6 +78,7 @@
self.tag = TagsFrame(app, "tag")
self.add_mode(self.tag)
+ self.tag.cumin_module = "configuration"
dashboard = PoolDashboard(app, "dashboard", self.object)
self.view.add_tab(dashboard)
Modified: branches/roles_II/cumin/python/cumin/inventory/main.py
===================================================================
--- branches/roles_II/cumin/python/cumin/inventory/main.py 2012-03-25 19:57:53 UTC (rev 5271)
+++ branches/roles_II/cumin/python/cumin/inventory/main.py 2012-03-25 20:24:08 UTC (rev 5272)
@@ -16,6 +16,7 @@
self.frame = InventoryFrame(app, "inventory")
self.app = app
+ self.frame.cumin_module = name
def init(self):
self.app.main_page.main.inventory = self.frame
Modified: branches/roles_II/cumin/python/cumin/inventory/system.py
===================================================================
--- branches/roles_II/cumin/python/cumin/inventory/system.py 2012-03-25 19:57:53 UTC (rev 5271)
+++ branches/roles_II/cumin/python/cumin/inventory/system.py 2012-03-25 20:24:08 UTC (rev 5272)
@@ -47,9 +47,11 @@
col = SystemTagsColumn(app, "Tags", app.model.com_redhat_cumin_grid.Node.Tags, "Tags")
self.add_column(col)
+ col.cumin_module = "configuration"
col = SystemCheckinColumn(app, "Checkin", app.model.com_redhat_cumin_grid.Node.Checkin, "Checkin")
self.add_column(col)
+ col.cumin_module = "configuration"
self.enable_csv_export()
@@ -74,6 +76,7 @@
configuration = SystemTags(app, "configuration", self.object)
self.view.add_tab(configuration)
+ configuration.cumin_module = "configuration"
def do_process(self, session):
try:
@@ -445,6 +448,7 @@
self.attr = attr
self.title = title
self.format_method = getattr(attr, "unit", None)
+ self.cumin_module = "configuration"
def get_field(self):
field = CheckinField(self.table.adapter, self.name)
Modified: branches/roles_II/cumin/python/cumin/main.py
===================================================================
--- branches/roles_II/cumin/python/cumin/main.py 2012-03-25 19:57:53 UTC (rev 5271)
+++ branches/roles_II/cumin/python/cumin/main.py 2012-03-25 20:24:08 UTC (rev 5272)
@@ -21,7 +21,7 @@
from util import *
from widgets import *
from authenticator import *
-from authorize import *
+from persona import CuminAuthorizator
from sage.catalog import Catalog
from sage.qmf.qmfoperations import QmfOperations
from sage.wallaby.wallabyoperations import WallabyOperations
@@ -76,14 +76,10 @@
self.form_defaults = self.CuminFormDefaults()
- # Persona methods are used to control what pages and/or
- # modules are present
-
+ # Persona value maps to xml definitions handled
+ # in persona.py
self.persona = persona
- self.personas = dict()
- self.personas["default"] = self._init_default_persona
- self.personas["grid"] = self._init_grid_persona
- self.personas["messaging"] = self._init_messaging_persona
+
self._page_links = list()
# we need the modules list to authorize
@@ -121,58 +117,45 @@
self.model.check()
self.database.check()
+
+ def _init_persona(self, modules):
- def _init_grid_persona(self):
- self.main_page = GridMainPage(self, "index.html")
+ # Determine the view based on which modules are enabled
+ if "messaging" in modules:
+ if "grid" in modules:
+ view = MainView(self, "main")
+ else:
+ view = MessagingMainView(self, "main")
+ else:
+ view = GridMainView(self, "main")
+
+ self.main_page = MainPage(self, "index.html", view)
self.add_page(self.main_page, add_to_link_set=True)
self.set_default_page(self.main_page)
-
- self.add_common_pages()
- import account
- import grid
- import inventory
- import usergrid
+ self.form_page = CuminFormPage(self, "form.html")
+ self.add_page(self.form_page)
- account.Module(self, "account")
- grid.Module(self, "grid")
- inventory.Module(self, "inventory")
- usergrid.Module(self, "usergrid")
+ self.add_page(StatFlashPage(self, "chart.json"))
+ self.add_page(FlashFullPage(self, "flashpage.html"))
- def _init_messaging_persona(self):
- self.main_page = MessagingMainPage(self, "index.html")
- self.add_page(self.main_page, add_to_link_set=True)
- self.set_default_page(self.main_page)
+ self.export_page = CuminExportPage(self, "csv")
+ self.add_page(self.export_page)
+
+ self.about_page = AboutPage(self, "about.html")
+ self.add_page(self.about_page)
- self.add_common_pages()
+ self.resource_page.protected = False
- import account
- import messaging
- import inventory
+ # Enable the modules that are associated with the
+ # persona (from persona.py)
+ for name in modules:
+ try:
+ m = __import__(name, globals())
+ m.Module(self, name)
+ except:
+ pass
- account.Module(self, "account")
- messaging.Module(self, "messaging")
- inventory.Module(self, "inventory")
-
- def _init_default_persona(self):
- self.main_page = MainPage(self, "index.html")
- self.add_page(self.main_page, add_to_link_set=True)
- self.set_default_page(self.main_page)
-
- self.add_common_pages()
-
- import account
- import messaging
- import grid
- import inventory
- import usergrid
-
- account.Module(self, "account")
- messaging.Module(self, "messaging")
- grid.Module(self, "grid")
- inventory.Module(self, "inventory")
- usergrid.Module(self, "usergrid")
-
def init(self, schema_version_check=True):
log.info("Initializing %s", self)
@@ -180,12 +163,14 @@
# the application can set a value for self.access_path.
# Alternatively, it can be an argument to the constructor.
self.authorizator = CuminAuthorizator(self, self.access_path)
- if self.access_path is not None and self.authorizator.map_is_empty():
- msg = "Access map does not exit or does not parse '%s'"
- raise Exception(msg % self.access_path)
+ try:
+ self.authorizator.set_persona(self.persona)
+ except:
+ msg = "Persona is not defined '%s'"
+ raise Exception(msg % self.persona)
self.authorize_cb = self.authorizator.authorize
- self.fallback_cb = self.authorizator.find_fallback
+ self.mainpage_cb = self.authorizator.find_mainpage
# Create RPC interfaces for QMF and aviary.
# These service have overlapping functionality,
@@ -240,12 +225,15 @@
self.database.init(schema_version_check)
self.server.init()
- # Create the correct persona
- if self.persona in self.personas:
- self.personas[self.persona]()
- else:
- self._init_default_persona()
+# Find a way to mark the pages, so that index.html is not
+# seeable by user in grid or default mode,
+# and so that usergrid is not visible in messaging mode.
+
+ # This will set up the main view and enable the
+ # modules that are associated with the persona
+ self._init_persona(self.authorizator.get_enabled_modules())
+
for module in self.modules:
module.init()
@@ -254,21 +242,6 @@
super(Cumin, self).init()
- def add_common_pages(self):
- self.form_page = CuminFormPage(self, "form.html")
- self.add_page(self.form_page)
-
- self.add_page(StatFlashPage(self, "chart.json"))
- self.add_page(FlashFullPage(self, "flashpage.html"))
-
- self.export_page = CuminExportPage(self, "csv")
- self.add_page(self.export_page)
-
- self.about_page = AboutPage(self, "about.html")
- self.add_page(self.about_page)
-
- self.resource_page.protected = False
-
def start(self):
log.info("Starting %s", self)
@@ -324,45 +297,10 @@
def init_test(self, test):
pass
-class GridMainPage(CuminPage, ModeSet):
- def __init__(self, app, name):
- super(GridMainPage, self).__init__(app, name)
-
- self.main = GridMainView(app, "main")
- self.add_mode(self.main)
- self.set_default_frame(self.main)
-
- self.page_html_class = "Cumin"
-
- def render_title(self, session):
- return self.get_title(session)
-
- def get_title(self, session):
- return "Administrator"
-
class GridMainView(CuminMainView):
def __init__(self, app, name):
super(GridMainView, self).__init__(app, name)
- #self.overview = GridOverviewFrame(app, "overview")
- #self.add_tab(self.overview)
-
-class MessagingMainPage(CuminPage, ModeSet):
- def __init__(self, app, name):
- super(MessagingMainPage, self).__init__(app, name)
-
- self.main = MessagingMainView(app, "main")
- self.add_mode(self.main)
- self.set_default_frame(self.main)
-
- self.page_html_class = "Cumin"
-
- def render_title(self, session):
- return self.get_title(session)
-
- def get_title(self, session):
- return "Administrator"
-
class MessagingMainView(CuminMainView):
def __init__(self, app, name):
super(MessagingMainView, self).__init__(app, name)
@@ -370,13 +308,21 @@
self.overview = MessagingOverviewFrame(app, "overview")
self.add_tab(self.overview)
-class MainPage(CuminPage, ModeSet):
+class MainView(CuminMainView):
def __init__(self, app, name):
+ super(MainView, self).__init__(app, name)
+
+ self.overview = OverviewFrame(app, "overview")
+ self.add_tab(self.overview)
+
+class MainPage(CuminPage, ModeSet):
+ def __init__(self, app, name, main_view):
super(MainPage, self).__init__(app, name)
- self.main = MainView(app, "main")
+ self.main = main_view
self.add_mode(self.main)
self.set_default_frame(self.main)
+ self.cumin_module = ["messaging", "grid"]
self.page_html_class = "Cumin"
@@ -386,13 +332,6 @@
def get_title(self, session):
return "Administrator"
-class MainView(CuminMainView):
- def __init__(self, app, name):
- super(MainView, self).__init__(app, name)
-
- self.overview = OverviewFrame(app, "overview")
- self.add_tab(self.overview)
-
# XXX Add qmf tab
class OverviewFrame(CuminFrame):
@@ -430,46 +369,12 @@
systems = TopSystemTable(app, "systems")
self.add_child(systems)
+ systems.cumin_module = "inventory"
submissions = TopSubmissionTable(app, "submissions")
self.add_child(submissions)
+ submissions.cumin_module = "grid"
- # XXX
-
- #queues = messaging.queue.TopQueueSet(app, "queues")
- #self.add_child(queues)
-
- #submissions = grid.submission.TopSubmissionSet(app, "submissions")
- #self.add_child(submissions)
-
- #systems = inventory.system.TopSystemSet(app, "systems")
- #self.add_child(systems)
-
-# don't appear to need this....
- # class Heading(CuminHeading):
- # def render_title(self, session):
- # return "Overview"
-
- # def render_icon_href(self, session):
- # return "resource?name=action-36.png"
-
-class GridOverviewFrame(OverviewFrame):
- def __init__(self, app, name):
- super(GridOverviewFrame, self).__init__(app, name)
-
- def get_overview_view(self, app):
- return GridOverviewView(app, "view")
-
-class GridOverviewView(Widget):
- def __init__(self, app, name):
- super(GridOverviewView, self).__init__(app, name)
-
- systems = TopSystemTable(app, "systems")
- self.add_child(systems)
-
- submissions = TopSubmissionTable(app, "submissions")
- self.add_child(submissions)
-
class MessagingOverviewFrame(OverviewFrame):
def __init__(self, app, name):
super(MessagingOverviewFrame, self).__init__(app, name)
Modified: branches/roles_II/cumin/python/cumin/messaging/main.py
===================================================================
--- branches/roles_II/cumin/python/cumin/messaging/main.py 2012-03-25 19:57:53 UTC (rev 5271)
+++ branches/roles_II/cumin/python/cumin/messaging/main.py 2012-03-25 20:24:08 UTC (rev 5272)
@@ -16,6 +16,7 @@
super(Module, self).__init__(app, name)
self.frame = MessagingFrame(self.app, "messaging")
+ self.frame.cumin_module = name
def init(self):
super(Module, self).init()
Added: branches/roles_II/cumin/python/cumin/persona.py
===================================================================
--- branches/roles_II/cumin/python/cumin/persona.py (rev 0)
+++ branches/roles_II/cumin/python/cumin/persona.py 2012-03-25 20:24:08 UTC (rev 5272)
@@ -0,0 +1,165 @@
+#!/usr/bin/env python
+import logging
+import os.path
+import re
+
+try:
+ import xml.etree.ElementTree as etree
+except ImportError:
+ import elementtree.ElementTree as etree
+
+log = logging.getLogger("cumin.authorize")
+
+class CuminGroup(object):
+ def __init__(self, name):
+ self.name = name
+ self.mainpage = "index.html"
+ self.allowed = [] # which modules the group can access
+
+class CuminPersona(object):
+ def __init__(self, name, auth):
+ self.name = name # may be handy to have this here
+
+ self.auth = auth.lower() == "true" # should groups be checked?
+ self.modules = [] # which modules are enabled
+ self.mapping = {} # dictionary of CuminGroup objects
+
+ def find_mainpage(self, group):
+ return self.mapping[group].mainpage
+
+ def lookup(self, group, module):
+ try:
+ if type(module) in (list, tuple):
+ return len(set(module) & \
+ set(self.mapping[group].allowed)) > 0
+ else:
+ return module in self.mapping[group].allowed
+ except KeyError:
+ return False
+
+class CuminPersonaMap(object):
+ def __init__(self):
+ log.info("Initializing %s", self.__class__.__name__)
+ self.personas = {}
+ self.filepath = None
+
+ def __repr__(self):
+ return ("%s %s" % ( self.__class__.__name__, self.filepath ))
+
+ def parse_personafile(self, filepath):
+ #TODO: handle exceptions during parsing
+ acctree = etree.ElementTree().parse(filepath)
+ for prec in acctree.getiterator('Persona'):
+ pkey = prec.attrib["name"]
+ auth = prec.attrib["auth"]
+ persona = CuminPersona(pkey, auth)
+ self.personas[pkey] = persona
+
+ for pchild in prec.getchildren():
+ if pchild.tag == "Module":
+ persona.modules.append(pchild.attrib["name"])
+ elif pchild.tag == "GroupAccess":
+ gkey = pchild.attrib["name"]
+ group = CuminGroup(gkey)
+ persona.mapping[gkey] = group
+ for gchild in pchild.getchildren():
+ if gchild.tag == "MainPage":
+ group.mainpage = gchild.attrib["name"]
+ elif gchild.tag == "ModuleAccess":
+ if gchild.attrib["name"] == "*":
+ group.allowed.extend(persona.modules)
+ else:
+ group.allowed.append(gchild.attrib["name"])
+
+class CuminAuthorizator(object):
+ def __init__(self, app, access_path):
+ self.app = app
+ self.access_path = access_path
+ log.info("Initializing %s", self)
+ self.personas = CuminPersonaMap()
+ self.persona = None
+
+ log.debug("Access file path is %s", access_path)
+ if os.path.isdir(access_path):
+ files = [os.path.join(access_path, x) \
+ for x in os.listdir(access_path)]
+ elif os.path.isfile(access_path):
+ files = [access_path]
+ else:
+ files = []
+ log.error("Path '%s' for access files does not exist!" % access_path)
+
+ for accfile in files:
+ if os.path.isfile(accfile) and \
+ os.path.splitext(accfile)[1] == ".xml":
+ try:
+ self.personas.parse_personafile(accfile)
+ except:
+ log.error("Access file '%s' does not parse!" % accfile)
+
+ def set_persona(self, name):
+ self.persona = self.personas.personas[name]
+
+ def is_enforcing(self):
+ return self.persona.auth
+
+ def find_mainpage(self, web_session):
+ # Find a main page for the current login session.
+ # If the user is part of multiple groups, just pick the
+ # first one. There may be a way to make a priority scheme here,
+ # but does it really matter?
+ try:
+ group = web_session.client_session.attributes['login_session'].group
+ except KeyError:
+ group = "nogroup"
+ if type(group) == type([]):
+ group = group[0]
+ return self.persona.find_mainpage(group)
+
+ def get_enabled_modules(self):
+ return self.persona.modules
+
+ def contains_valid_group(self, groups):
+ for g in groups:
+ if g in self.persona.mapping:
+ return True
+ return False
+
+ def authorize(self, web_session, widget):
+ if not hasattr(widget, "cumin_module") or \
+ widget.cumin_module is None:
+ # no module for this widget, we have to allow it
+ return True
+
+ # We can't logically be authorized for a module we haven't even
+ # enabled! This may occur when parts of a display have
+ # associated themselves with a module explicitly.
+ # (like a column in a table that is only valid if a
+ # particular module has been loaded).
+ if type(widget.cumin_module) in (list, tuple):
+ if len(set(widget.cumin_module) & set(self.persona.modules)) == 0:
+ return False
+ elif not widget.cumin_module in self.persona.modules:
+ return False
+
+ if not self.is_enforcing():
+ # Auth checks against group are off.
+ return True
+
+ try:
+ group = web_session.client_session.attributes['login_session'].group
+ except KeyError:
+ group = "nogroup"
+
+ if type(group) == type([]):
+ for g in group:
+ if self.persona.lookup(g, widget.cumin_module):
+ log.debug("Allowing %s authorization for %s ",
+ widget.cumin_module, group)
+ return True
+ else:
+ return self.persona.lookup(group, widget.cumin_module)
+
+ log.debug("Denying %s authorization for %s ", widget.my_name, group)
+ return False
+
Modified: branches/roles_II/cumin/python/cumin/usergrid/main.py
===================================================================
--- branches/roles_II/cumin/python/cumin/usergrid/main.py 2012-03-25 19:57:53 UTC (rev 5271)
+++ branches/roles_II/cumin/python/cumin/usergrid/main.py 2012-03-25 20:24:08 UTC (rev 5272)
@@ -11,3 +11,4 @@
self.app.user_grid_page = MainPage(self.app, "usergrid.html")
self.app.add_page(self.app.user_grid_page, add_to_link_set=True)
+ self.app.user_grid_page.cumin_module = self.name
Modified: branches/roles_II/cumin/python/cumin/widgets.py
===================================================================
--- branches/roles_II/cumin/python/cumin/widgets.py 2012-03-25 19:57:53 UTC (rev 5271)
+++ branches/roles_II/cumin/python/cumin/widgets.py 2012-03-25 20:24:08 UTC (rev 5272)
@@ -1362,7 +1362,7 @@
# of an infinite redirect loop.
cls, value, traceback = sys.exc_info()
if self.app.authorizator.is_enforcing():
- mainpage = self.app.authorizator.find_fallback(session)
+ mainpage = self.app.authorizator.find_mainpage(session)
if not mainpage.startswith("/"):
mainpage = "/" + mainpage
else:
Modified: branches/roles_II/wooly/python/wooly/pages.py
===================================================================
--- branches/roles_II/wooly/python/wooly/pages.py 2012-03-25 19:57:53 UTC (rev 5271)
+++ branches/roles_II/wooly/python/wooly/pages.py 2012-03-25 20:24:08 UTC (rev 5272)
@@ -151,10 +151,10 @@
return sess.marshal()
def redirect_on_not_authorized(self, session):
- fallback_page = self.app.fallback_cb(session)
- if fallback_page in self.app.pages_by_name:
- log.debug("Not authorized, redirecting to %s", fallback_page)
- page = self.app.pages_by_name[fallback_page]
+ mainpage = self.app.mainpage_cb(session)
+ if mainpage in self.app.pages_by_name:
+ log.debug("Not authorized, redirecting to %s", mainpage)
+ page = self.app.pages_by_name[mainpage]
sess = Session(page)
self.redirect.set(session, sess.marshal())
Modified: branches/roles_II/wooly/python/wooly/table.py
===================================================================
--- branches/roles_II/wooly/python/wooly/table.py 2012-03-25 19:57:53 UTC (rev 5271)
+++ branches/roles_II/wooly/python/wooly/table.py 2012-03-25 20:24:08 UTC (rev 5272)
@@ -70,6 +70,7 @@
writer = Writer()
for column in self.get_visible_columns(session):
+
writer.write(column.render(session))
return writer.to_string()
@@ -272,7 +273,8 @@
writer = Writer()
for column in self.table.get_visible_columns(session):
- writer.write(column.header.render(session))
+ if self.app.authorize_cb(session, column):
+ writer.write(column.header.render(session))
return writer.to_string()
@@ -285,7 +287,8 @@
writer = Writer()
for column in self.table.get_visible_columns(session):
- writer.write(column.cell.render(session, record))
+ if self.app.authorize_cb(session, column):
+ writer.write(column.cell.render(session, record))
return writer.to_string()
Modified: branches/roles_II/wooly/python/wooly/widgets.py
===================================================================
--- branches/roles_II/wooly/python/wooly/widgets.py 2012-03-25 19:57:53 UTC (rev 5271)
+++ branches/roles_II/wooly/python/wooly/widgets.py 2012-03-25 20:24:08 UTC (rev 5272)
@@ -58,7 +58,8 @@
writer = Writer()
for tab in self.__tabs:
- self.__tab_tmpl.render(writer, session, tab)
+ if self.app.authorize_cb(session, tab):
+ self.__tab_tmpl.render(writer, session, tab)
return writer.to_string()
12 years, 1 month