r5134 - in trunk/cumin: bin python/cumin
by tmckay@fedoraproject.org
Author: tmckay
Date: 2011-11-11 19:28:53 +0000 (Fri, 11 Nov 2011)
New Revision: 5134
Added:
trunk/cumin/python/cumin/errors.py
Modified:
trunk/cumin/bin/cumin
trunk/cumin/bin/cumin-data
trunk/cumin/bin/cumin-web
Log:
Additional error checking, log general message to syslog on master error.
Modified: trunk/cumin/bin/cumin
===================================================================
--- trunk/cumin/bin/cumin 2011-11-11 15:08:34 UTC (rev 5133)
+++ trunk/cumin/bin/cumin 2011-11-11 19:28:53 UTC (rev 5134)
@@ -7,6 +7,8 @@
import signal
import traceback
from datetime import datetime, timedelta
+import syslog
+from cumin.errors import CuminErrors
home = os.environ.get("CUMIN_HOME", os.path.normpath("/usr/share/cumin"))
sys.path.append(os.path.join(home, "python"))
@@ -25,6 +27,7 @@
def log_parse_errors(r):
msg = os.fdopen(r, "r").readlines()
if len(msg) > 0:
+ _syslog.log()
log.error("".join(msg))
return 1
return 0
@@ -40,6 +43,14 @@
prog_string = "".join([" "+x for x in args])
return args, prog_string
+class _syslog(object):
+ enabled = False
+ @classmethod
+ def log(cls):
+ if _syslog.enabled:
+ home = os.environ.get("CUMIN_HOME", os.path.normpath("/usr/share/cumin"))
+ syslog.syslog("cumin: master script exited with errors, see %s/master.log" % home)
+
def main():
# tuple indices, for clarity
@@ -72,15 +83,18 @@
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("--data_options", dest="data_options", default="", type=str,
+ 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,
+ 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("--syslog", dest="syslog", action="store_true", default=False,
+ help="Log general error notfications to syslog. Intended for systemd")
+
(options, args) = parser.parse_args()
except SystemExit:
options = args = None
@@ -91,19 +105,26 @@
sys.stderr = sys.__stderr__
# Parse may have failed, in which case make a quick check for options ourselves
- console = (options and options.console) or "--console" in sys.argv[1:]
+ if options:
+ _syslog.enabled = options.syslog
+ console = options.console
+ else:
+ _syslog.enabled = "--syslog" in sys.argv[1:]
+ console = "--console" in sys.argv[1:]
if console:
log_dest = sys.stderr
else:
log_dest = os.path.join(home, "log", "master.log")
enable_logging("cumin.master", logging.INFO, log_dest)
+
# Parser exited, either on --help or with errors
if not options:
return log_parse_errors(r)
if len(args) != 0:
log.error("Extra arguments:" + "".join([" "+arg for arg in args]))
+ _syslog.log()
return 1
# Get our list of cumin-web and data instances
@@ -153,19 +174,23 @@
# been started, do not start the remaining.
# Note, signals that cause termination will result in
# a negative error code, we treat those as "normal"
+ err = CuminErrors.translate(poll)
if poll > 0 and poll & 1:
- log.error("Subprocess failed init checks (pid %s), "\
- "status %s, check subprocess logs for details" %\
- (app[PROCESS].pid, str(poll)))
+ log.error("Subprocess (%s) failed init checks "\
+ "with status %s (%s), %s"\
+ % (app[PROCESS].pid, poll, err[0], err[1]))
+ log.info("Subprocess logs may contain more details.")
log.info("Stopping cumin")
+ _syslog.log()
app[PROCESS] = None
return_code = 2
complete = len(apps)
break
else:
- log.warn("Subprocess exited (pid %s), status %s, "\
- "check subprocess logs for details" %\
- (app[PROCESS].pid, str(poll)))
+ log.warn("Subprocess (%s) exited with status %s (%s), %s"\
+ % (app[PROCESS].pid, poll, err[0], err[1]))
+ if poll != 0:
+ log.info("Subprocess logs may contain more details.")
if options.init_only:
app[PROCESS] = None
complete += 1
Modified: trunk/cumin/bin/cumin-data
===================================================================
--- trunk/cumin/bin/cumin-data 2011-11-11 15:08:34 UTC (rev 5133)
+++ trunk/cumin/bin/cumin-data 2011-11-11 19:28:53 UTC (rev 5134)
@@ -12,6 +12,7 @@
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__
@@ -19,7 +20,7 @@
def process_classes(mint, values, section_name, on_empty=None):
- return_code = 0
+ return_code = CuminErrors.NO_ERROR
pkgs = set()
if values and len(values) > 0:
@@ -32,7 +33,7 @@
log.error("Configuration section '%s',"\
" class name '%s' is badly formed"\
% (section_name, cls_str.strip()))
- return_code = 1
+ return_code = CuminErrors.PARSE_ERROR
break
try:
@@ -58,7 +59,7 @@
def process_agents(values, section_name):
- return_code = 0
+ return_code = CuminErrors.NO_ERROR
agents = set()
if values and len(values) > 0:
@@ -75,7 +76,7 @@
log.error("Configuration section '%s',"\
" agent name '%s' is badly formed"\
% (section_name, agent_str))
- return_code = 1
+ return_code = CuminErrors.PARSE_ERROR
break
if len(agent) >= 1:
vendor = agent[0]
@@ -96,7 +97,7 @@
def main():
passed_init = 1
- return_code = 0
+ 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
@@ -129,7 +130,7 @@
print_exc()
pipeThread = None
- class EarlyReturn(Exception):
+ class ArgError(Exception):
pass
try:
@@ -166,7 +167,7 @@
if len(args) != 0:
log.error("Extra arguments:" + "".join([" "+arg for arg in args]))
- raise EarlyReturn
+ raise ArgError
model_dir = os.path.join(config.home, "model")
@@ -233,27 +234,30 @@
except KeyboardInterrupt:
log.info("Received SIGINT")
- except (SystemExit, EarlyReturn):
+ except SystemExit:
if "--help" not in sys.argv:
- log.error("Error in options, arguments, or config values")
- return_code = 1
+ 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 = 3
+ return_code = CuminErrors.DATABASE_ERROR
except SchemaMissing:
log.info("Run 'cumin-admin create-schema' as root")
- return_code = 4
+ return_code = CuminErrors.SCHEMA_ERROR
except SchemaVersion:
log.info("Run 'cumin-admin upgrade-schema' as root")
- return_code = 5
+ return_code = CuminErrors.SCHEMA_VER_ERROR
except:
print_exc()
- return_code = 2
+ return_code = CuminErrors.UNHANDLED_ERROR
if mint:
mint.stop()
Modified: trunk/cumin/bin/cumin-web
===================================================================
--- trunk/cumin/bin/cumin-web 2011-11-11 15:08:34 UTC (rev 5133)
+++ trunk/cumin/bin/cumin-web 2011-11-11 19:28:53 UTC (rev 5134)
@@ -11,6 +11,7 @@
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__
@@ -50,7 +51,7 @@
def main():
passed_init = 1
- return_code = 0
+ 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
@@ -84,8 +85,8 @@
print_exc()
pipeThread = None
- # Use EarlyReturn to jump to the finally block and exit
- class EarlyReturn(Exception):
+ # Use ArgError to jump to the finally block and exit
+ class ArgError(Exception):
pass
try:
@@ -121,7 +122,7 @@
if len(args) != 0:
log.error("Extra arguments:" + "".join([" "+arg for arg in args]))
- raise EarlyReturn
+ raise ArgError
broker_uris = [x.strip() for x in opts.brokers.split(",")]
authmech = [x.strip() for x in values.auth.split(";")]
@@ -159,37 +160,38 @@
sleep(1)
if not cumin.server_alive():
print "web server has stopped, exiting..."
- return_code = 1
+ log.error("Web server process has stopped")
+ return_code = CuminErrors.WEB_SERVER_ERROR
break
except KeyboardInterrupt:
log.info("Received SIGINT")
pass
- except (SystemExit, EarlyReturn):
+ except SystemExit:
if "--help" not in sys.argv:
- log.error("Error in options, arguments, or config values")
- return_code = 1
+ log.error("Error in options")
+ return_code = CuminErrors.PARSE_ERROR
- except EarlyReturn:
- return_code = 1
+ 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 = 3
+ return_code = CuminErrors.DATABASE_ERROR
except SchemaMissing:
log.info("Run 'cumin-admin create-schema' as root")
- return_code = 4
+ return_code = CuminErrors.SCHEMA_ERROR
except SchemaVersion:
log.info("Run 'cumin-admin upgrade-schema' as root")
- return_code = 5
+ return_code = CuminErrors.SCHEMA_VER_ERROR
except:
print_exc()
- return_code = 2
+ return_code = CuminErrors.UNHANDLED_ERROR
if cumin:
cumin.stop()
Added: trunk/cumin/python/cumin/errors.py
===================================================================
--- trunk/cumin/python/cumin/errors.py (rev 0)
+++ trunk/cumin/python/cumin/errors.py 2011-11-11 19:28:53 UTC (rev 5134)
@@ -0,0 +1,46 @@
+# Intended for use by top level scripts like cumin, cumin-web and cumin-data
+# for reporting errors during startup.
+class CuminErrors(object):
+ NO_ERROR = 0
+ PARSE_ERROR = 1
+ UNHANDLED_ERROR = 2
+ DATABASE_ERROR = 3
+ SCHEMA_ERROR = 4
+ SCHEMA_VER_ERROR = 5
+ WEB_SERVER_ERROR = 6
+
+ errors = \
+ {NO_ERROR: ("no error", "normal operation"),
+ PARSE_ERROR: \
+ ("parse error",
+ "error in options, arguments, or config values"),
+ UNHANDLED_ERROR: \
+ ("unhandled error",
+ "*.stderr or *.stdout logs may contain details"),
+ DATABASE_ERROR: \
+ ("database error",
+ "run 'cumin-database check' as root for more information"),
+ SCHEMA_ERROR: \
+ ("schema error",
+ "run 'cumin-admin create-schema' as root"),
+ SCHEMA_VER_ERROR: \
+ ("schema version error",
+ "run 'cumin-admin upgrade-schema' as root"),
+ WEB_SERVER_ERROR: \
+ ("web server error",
+ "web server process has exited")
+ }
+
+ @classmethod
+ def translate(cls, status):
+ s = status
+ # low bit indicates wheter error was during init or not.
+ # shift right for value (if it's not a signal)
+ if s > 0:
+ s = s >> 1
+ if s in CuminErrors.errors:
+ return CuminErrors.errors[s]
+ elif s < 0:
+ return ("received a signal", "unhandled")
+ else:
+ return ("unrecognized error", "check logs for details")
12 years, 6 months
r5133 - trunk/cumin/etc
by tmckay@fedoraproject.org
Author: tmckay
Date: 2011-11-11 15:08:34 +0000 (Fri, 11 Nov 2011)
New Revision: 5133
Added:
trunk/cumin/etc/cumin.service
Log:
Add cumin.service file for use with systemd (F15+)
Added: trunk/cumin/etc/cumin.service
===================================================================
--- trunk/cumin/etc/cumin.service (rev 0)
+++ trunk/cumin/etc/cumin.service 2011-11-11 15:08:34 UTC (rev 5133)
@@ -0,0 +1,10 @@
+[Unit]
+Description=MRG Management console
+After=postgresql.target
+
+[Service]
+Type=simple
+ExecStart=/usr/bin/cumin
+
+[Install]
+WantedBy=multi-user.target
12 years, 6 months
r5132 - branches/lucidity/cumin/etc
by tmckay@fedoraproject.org
Author: tmckay
Date: 2011-11-10 19:21:59 +0000 (Thu, 10 Nov 2011)
New Revision: 5132
Modified:
branches/lucidity/cumin/etc/cumin.conf
Log:
Add colon to aviary-cert template
svn merge -c 5131 svn+ssh://svn.fedorahosted.org/svn/cumin/trunk .
Modified: branches/lucidity/cumin/etc/cumin.conf
===================================================================
--- branches/lucidity/cumin/etc/cumin.conf 2011-11-10 18:59:01 UTC (rev 5131)
+++ branches/lucidity/cumin/etc/cumin.conf 2011-11-10 19:21:59 UTC (rev 5132)
@@ -43,7 +43,7 @@
# Full path to certificate file used for ssl communication with aviary severs.
# This is necessary to communicate with any aviary server using the https scheme.
-#aviary-cert
+#aviary-cert:
# Optional full path to root certificate file used for server certificate
# validation with aviary servers using ssl. If this value is not specified, only
12 years, 6 months
r5131 - trunk/cumin/etc
by tmckay@fedoraproject.org
Author: tmckay
Date: 2011-11-10 18:59:01 +0000 (Thu, 10 Nov 2011)
New Revision: 5131
Modified:
trunk/cumin/etc/cumin.conf
Log:
Missing colon on aviary-cert template
Modified: trunk/cumin/etc/cumin.conf
===================================================================
--- trunk/cumin/etc/cumin.conf 2011-11-10 15:24:35 UTC (rev 5130)
+++ trunk/cumin/etc/cumin.conf 2011-11-10 18:59:01 UTC (rev 5131)
@@ -43,7 +43,7 @@
# Full path to certificate file used for ssl communication with aviary severs.
# This is necessary to communicate with any aviary server using the https scheme.
-#aviary-cert
+#aviary-cert:
# Optional full path to root certificate file used for server certificate
# validation with aviary servers using ssl. If this value is not specified, only
12 years, 6 months
r5130 - branches/noflash/cumin/resources
by croberts@fedoraproject.org
Author: croberts
Date: 2011-11-10 15:24:35 +0000 (Thu, 10 Nov 2011)
New Revision: 5130
Modified:
branches/noflash/cumin/resources/app.js
Log:
Adding the <chart>.destroy() memory leak fix for the pie charts.
Modified: branches/noflash/cumin/resources/app.js
===================================================================
--- branches/noflash/cumin/resources/app.js 2011-11-09 21:22:44 UTC (rev 5129)
+++ branches/noflash/cumin/resources/app.js 2011-11-10 15:24:35 UTC (rev 5130)
@@ -648,8 +648,10 @@
updatePieChart = function (piediv, vals, colors) {
var data = vals;
- $(piediv).empty();
- jQuery.jqplot (piediv, [data],
+ if(allCharts[piediv]) {
+ allCharts[piediv].destroy();
+ }
+ allCharts[piediv] = jQuery.jqplot (piediv, [data],
{
grid: {
drawBorder: false,
12 years, 6 months
r5129 - branches/noflash/cumin/python/cumin
by croberts@fedoraproject.org
Author: croberts
Date: 2011-11-09 21:22:44 +0000 (Wed, 09 Nov 2011)
New Revision: 5129
Removed:
branches/noflash/cumin/python/cumin/charts.py
Log:
Removing charts.py since it is no longer used.
Deleted: branches/noflash/cumin/python/cumin/charts.py
===================================================================
--- branches/noflash/cumin/python/cumin/charts.py 2011-11-09 21:21:29 UTC (rev 5128)
+++ branches/noflash/cumin/python/cumin/charts.py 2011-11-09 21:22:44 UTC (rev 5129)
@@ -1,439 +0,0 @@
-import logging
-
-from cairo import *
-from random import random
-from time import time
-from math import sqrt, pi, ceil
-
-from formats import *
-from util import *
-
-log = logging.getLogger("cumin.chart")
-
-class CuminPieChart(object):
- def __init__(self, radius=400):
- self.width = radius * 2
- self.height = self.width
- self.centerx = radius
- self.centery = radius
- self.radius = radius
-
- def plot_pie(self, slices, colors):
- surface = ImageSurface(FORMAT_ARGB32, int(self.width), int(self.height))
- cr = Context(surface)
- cr.set_line_width(2)
-
- total = float(sum(slices))
-
- if not total:
- # draw a grey placeholder circle
- cr.new_path()
- cr.arc(self.centerx, self.centery,
- self.radius, 0, 2 * pi)
- cr.close_path()
- cr.set_source_rgba(0, 0, 0, 0.1)
- cr.stroke()
- return surface
-
- wedge = cum_wedges = end = 0.0
-
- # are we going to draw more than one slice
- draw_border = sum([1 for x in slices if x > 0]) > 1
-
- for slice, color in zip(slices, colors):
- if slice > 0:
- wedge = slice / total
-
- start = end
- end = (cum_wedges + wedge) * 2 * pi
- cum_wedges += wedge
-
- # draw the wedge
- self.draw_slice_path(cr, self.centerx, self.centery,
- self.radius, start, end)
- cr.set_source_rgb(*color)
- cr.fill()
-
- # draw a white border
- if draw_border:
- self.draw_slice_path(cr, self.centerx, self.centery,
- self.radius, start, end)
- cr.set_source_rgb(1,1,1)
- cr.stroke()
-
- return surface
-
- def draw_slice_path(self, cr, x, y, radius, start, end):
- cr.new_path()
- cr.move_to(x, y)
- cr.arc(x, y, radius, start, end)
- cr.close_path()
-
-class HeatMapChart(object):
- def __init__(self, width=400, height=400):
- self.width = width # final width
- self.height = height
- self.max_width = width # max width
- self.max_height = height
- self.cols = 0 # columns
- self.rows = 0
- self.max_size = 28 # size of each slot
- self.surface = None
- self.gap = 3
-
- def plot_colored_shape(self, interior, shape, width, height):
- surface = ImageSurface(FORMAT_ARGB32, int(width), int(height))
- cr = Context(surface)
- cr.set_line_width(1)
-
- cr.set_source_rgba(1.0, 1.0, 1.0, 1.0)
- cr.rectangle(0, 0, width - 1, height - 1)
- cr.fill()
-
- cr.set_line_width(2)
- self._plot_shape(cr, interior, shape, 0, 0, width, height)
- return surface
-
- def plot_colored_rect(self, interior, width, height):
- surface = ImageSurface(FORMAT_ARGB32, int(width), int(height))
- cr = Context(surface)
- cr.set_line_width(1)
-
- cr.set_source_rgb(*interior)
- cr.rectangle(0, 0, width - 1, height - 1)
- cr.fill()
- return surface
-
- def plot_state(self, state, width, height):
- surface = ImageSurface(FORMAT_ARGB32, int(width), int(height))
- cr = Context(surface)
- cr.set_line_width(2)
-
- self._plot_square(cr, (0.7, 0.7, 0.7), state, 0, 0, width, height)
- return surface
-
- def _plot_square(self, cr, colors, state, x, y, width, height):
- if state == "Unclaimed":
- shape = "box"
- elif state == "Claimed":
- shape = "solid"
- elif state in ("Owner", "Unavailable"):
- shape = "diagonal"
- elif state in ("Matched", "Preempting", "Preempting/Matched"):
- shape = "filled_triangle"
- else:
- shape = "box"
-
- self._plot_shape(cr, colors, shape, x, y, width, height)
-
- def _plot_shape(self, cr, colors, shape, x, y, width, height):
- cr.set_source_rgb(*colors)
- #cr.move_to(x, y)
- cr.rectangle(x, y, width - self.gap, height - self.gap)
-
- if shape == "box": # leave empty
- cr.stroke()
- elif shape == "solid": # solid fill
- cr.fill()
- elif shape == "diagonal": # diagonal line
- cr.move_to(x, y)
- cr.line_to(x + width - self.gap, y + height - self.gap)
- cr.stroke()
- elif shape == "filled_triangle": # triangle
- cr.stroke()
- cr.move_to(x + width - self.gap, y)
- cr.line_to(x, y + height - self.gap)
- cr.line_to(x + width - self.gap, y + height - self.gap)
- cr.close_path()
- cr.fill()
-
- def plot_shapes(self, shape_info, zl):
- count = len(shape_info)
- slot_size = self.slot_size(count, zl)
- x = 0
- y = 0
- col = 0
- self.rows = 1
- # the width and height depend on the number of slots
- self.surface = ImageSurface(FORMAT_ARGB32, int(self.width), int(self.height))
- cr = Context(self.surface)
-
- cr.set_line_width( zl == 1 and 1 or 2 )
-
- for slot in shape_info:
- interior = slot["color"]
- shape = slot["shape"]
-
- if col >= self.cols:
- x = 0
- y = y + slot_size
- col = 0
- self.rows = self.rows + 1
-
- self._plot_shape(cr, interior, shape, x, y, slot_size, slot_size)
-
- x = x + slot_size
- col = col + 1
- return slot_size
-
- def slot_size(self, count, zoom=1):
- sq = sqrt(count)
- cols = int(sq)
- if sq > cols:
- cols = cols + 1
- size = int(self.width * zoom / cols)
- if size < 2:
- size = 2
- if size > self.max_size * zoom:
- size = self.max_size * zoom
-
- self.width = int((size * cols) + 1)
- self.height = int((ceil(count * 1.0 / cols) * size) + 1)
- self.cols = cols
- return size
-
- def write(self, writer):
- self.surface.write_to_png(writer)
-
-class TimeSeriesChart(object):
- def __init__(self, width, height, interval=0):
- self.width = width - 40
- self.height = height - 20
- real_height = height + ((interval > 10) and 12 or 0)
- self.surface = ImageSurface(FORMAT_ARGB32, int(width), int(real_height))
- self.surface.set_device_offset(1.5, 5.5)
- self.x_max = 1
- self.x_min = 0
- self.y_max = 1
- self.y_min = 0
-
- def plot_values(self, samples, color=(0, 0, 0)):
- cr = Context(self.surface)
- cr.set_line_width(1.5)
- cr.set_source_rgba(color[0], color[1], color[2], 0.66)
-
- tnow = time()
- points = list()
-
- for dt, value, dev in samples:
- if value is None:
- continue
-
- t = secs(dt)
-
- # prevent line from drawing off right side of grid
- if tnow - t < 0:
- t = tnow
-
- x = self.width - ((tnow - t) / float(self.x_max)) * self.width
- y = self.height - (value / float(self.y_max)) * self.height
- cr.line_to(x, y)
- if x < 0:
- break
- points.append([int(x), int(y), "%.2f" % value])
-
- cr.stroke()
- return points
-
- def plot_ticks(self, samples, color=(0, 0, 0)):
- cr = Context(self.surface)
- cr.set_line_width(1.5)
-
- tnow = time()
- dot_size = max(int(self.height / 100), 2)
- half_dot = int(dot_size / 2)
-
- for dt, value, dev in samples:
- if value is None:
- continue
-
- t = secs(dt)
-
- # prevent line from drawing off right side of grid
- if tnow - t < 0:
- t = tnow
-
- cr.set_source_rgba(color[0], color[1], color[2], 0.66)
- x = self.width - ((tnow - t) / float(self.x_max)) * self.width
- y = self.height - (value / float(self.y_max)) * self.height
- cr.move_to(x, y)
- cr.rectangle(x - half_dot, y - half_dot, dot_size, dot_size)
- cr.fill()
-
- if dev:
- cr.set_source_rgba(0, 0, 0, 0.1)
- half_dev = int(((float(dev) / float(self.y_max)) * self.height) / 2)
- cr.move_to(x - dot_size, y - half_dev)
- cr.line_to(x + dot_size, y - half_dev)
-
- cr.move_to(x, y - half_dev)
- cr.line_to(x, y + half_dev)
-
- cr.move_to(x - dot_size, y + half_dev)
- cr.line_to(x + dot_size, y + half_dev)
-
- cr.stroke()
-
- def plot_legend(self, titles, colors):
- cr = Context(self.surface)
- cr.set_line_width(1.5)
- title_xy = dict()
-
- for i, item in enumerate(zip(titles, colors)):
- title, color = item
- y = 16 + i * 16
-
- cr.set_source_rgba(1, 1, 1, 0.75)
- cr.rectangle(4, y - 12, 16 + 6.5 * len(title), 16)
- cr.fill()
- cr.stroke()
-
- cr.set_source_rgb(*color)
- cr.rectangle(8, y, 8, -8)
- cr.fill()
- cr.stroke()
-
- cr.move_to(20, y)
- cr.set_source_rgb(0, 0, 0)
- cr.show_text(title)
- cr.stroke()
-
- width, height = cr.text_extents(title)[2:4]
- title_xy[color] = [width, y]
- return title_xy
-
- def plot_frame(self, color=(0.8, 0.8, 0.8)):
- cr = Context(self.surface)
- cr.set_line_width(1)
- cr.set_source_rgb(*color)
-
- cr.move_to(self.width, 0)
- cr.line_to(self.width, self.height)
- cr.line_to(0, self.height)
-
- cr.stroke()
-
- def plot_interval(self, interval):
- if interval > 10:
- cr = Context(self.surface)
- cr.set_line_width(0.2)
- cr.set_source_rgb(0.2, 0.2, 0.2)
-
- cr.move_to(2, self.height + 24)
- cr.show_text("* Samples averaged over %i second interval" % interval)
- cr.stroke()
-
- def plot_x_axis(self, intervals, step):
- cr = Context(self.surface)
- cr.set_line_width(0.2)
- cr.set_source_rgb(0.6, 0.6, 0.6)
-
- interval = self.width / float(intervals)
- absmax = self.x_max - self.x_min
-
- for i in range(0, intervals + 1):
- x = self.width - (i * interval)
-
- cr.move_to(x, 0)
- cr.line_to(x, self.height + 12)
- cr.move_to(x + 2, self.height + 12)
-
- if i % step == 0:
- value = absmax - (absmax * x / float(self.width))
- text = fmt_duration_brief(value)
- if text:
- cr.show_text(text)
-
- cr.stroke()
-
- def plot_y_axis(self, intervals, step):
- cr = Context(self.surface)
- cr.set_line_width(0.2)
- cr.set_source_rgb(0.6, 0.6, 0.6)
-
- interval = self.height / float(intervals)
-
- for i in range(0, intervals + 1):
- y = self.height - (i * interval)
-
- cr.move_to(0, y)
- cr.line_to(self.width + 3, y)
- cr.move_to(self.width + 4, y + 3)
-
- if i % step == 0:
- fraction = (self.height - y) / float(self.height)
- value = fraction * self.y_max - self.y_min
- value = int(round(value + self.y_min))
-
- if value >= 1000000:
- svalue = "%.2fm" % (round(value / 1000000.0, 2))
- elif value >= 10000:
- svalue = "%ik" % int(round(value / 1000.0, -1))
- else:
- svalue = str(value)
-
- cr.show_text(svalue)
-
- cr.stroke()
-
- def write(self, writer):
- self.surface.write_to_png(writer)
-
-class StackedValueChart(TimeSeriesChart):
- def __init__(self, width, height, legend_height = 0):
- super(StackedValueChart, self).__init__(width, height)
-
- if legend_height:
- self.surface = ImageSurface(FORMAT_ARGB32, int(width), int(height + legend_height))
- self.surface.set_device_offset(1.5, 5.5)
-
- self.legend_height = legend_height
- self.bar_width = 2
-
- def plot_values(self, dt, samples, colors):
- cr = Context(self.surface)
- cr.set_line_width(self.bar_width)
-
- tnow = time()
- y = self.height
- v = 0
- for value, color in zip(samples, colors):
- if value is None:
- continue
-
- t = secs(dt)
-
- if tnow - t < 0:
- t = tnow
-
- x = self.width - ((tnow - t) / float(self.x_max)) * self.width
- cr.move_to(x, y)
- cr.set_source_rgba(color[0], color[1], color[2], 0.66)
-
- v = v + value
- y = self.height - (v / float(self.y_max)) * self.height
- cr.line_to(x, y)
- cr.stroke()
-
- def plot_legend(self, titles, colors):
- cr = Context(self.surface)
-
- for i, item in enumerate(zip(titles, colors)):
- title, color = item
- y = self.height + 26 + i * 16
-
- cr.set_source_rgba(1, 1, 1, 0.75)
- cr.rectangle(4, y - 12, 16 + 6.5 * len(title), 16)
- cr.fill()
- cr.stroke()
-
- cr.set_source_rgb(*color)
- cr.rectangle(8, y, 8, -8)
- cr.fill()
- cr.stroke()
-
- cr.move_to(20, y)
- cr.set_source_rgb(0, 0, 0)
- cr.show_text(title)
- cr.stroke()
-
12 years, 6 months
r5128 - branches/noflash/cumin/python/cumin
by croberts@fedoraproject.org
Author: croberts
Date: 2011-11-09 21:21:29 +0000 (Wed, 09 Nov 2011)
New Revision: 5128
Modified:
branches/noflash/cumin/python/cumin/main.py
branches/noflash/cumin/python/cumin/stat.py
Log:
Removing unused code that was used to render the png charts.
Modified: branches/noflash/cumin/python/cumin/main.py
===================================================================
--- branches/noflash/cumin/python/cumin/main.py 2011-11-09 20:30:18 UTC (rev 5127)
+++ branches/noflash/cumin/python/cumin/main.py 2011-11-09 21:21:29 UTC (rev 5128)
@@ -4,8 +4,7 @@
from mint import *
from parsley.loggingex import *
-from stat import StatChartPage, StatStackedPage, \
- StatFlashPage, FlashFullPage
+from stat import StatFlashPage, FlashFullPage
from wooly import Application, Session, Page
from wooly.pages import ResourcePage
from wooly.parameters import IntegerParameter
@@ -25,7 +24,6 @@
from sage.qmfoperations import QmfOperations
from sage.aviaryoperations import AviaryOperations
from wooly import Session
-from cumin.stat import PieChartPage
from cumin.widgets import AboutPage
strings = StringCatalog(__file__)
@@ -182,9 +180,6 @@
self.form_page = CuminFormPage(self, "form.html")
self.add_page(self.form_page)
- self.add_page(StatChartPage(self, "stats.png"))
- self.add_page(StatStackedPage(self, "stacked.png"))
- self.add_page(PieChartPage(self, PieChartPage.PAGE_NAME))
self.add_page(StatFlashPage(self, "chart.json"))
self.add_page(FlashFullPage(self, "flashpage.html"))
Modified: branches/noflash/cumin/python/cumin/stat.py
===================================================================
--- branches/noflash/cumin/python/cumin/stat.py 2011-11-09 20:30:18 UTC (rev 5127)
+++ branches/noflash/cumin/python/cumin/stat.py 2011-11-09 21:21:29 UTC (rev 5128)
@@ -14,7 +14,6 @@
from cumin.model import CuminStatistic, SamplesSqlAdapter
from cumin.widgets import StateSwitch
from wooly.template import WidgetTemplate
-from cumin.charts import CuminPieChart, TimeSeriesChart, StackedValueChart
from cumin.util import calc_rate, secs, nvl
from cumin.OpenFlashChart import Element, Chart
@@ -276,8 +275,7 @@
self.__files[name] = {"time": datetime.now(), "file": file, "cookie": args}
return file
-class PieChartPage(Page):
- # handles pie.png request
+class PieChartPage(object):
PAGE_NAME = "pie.png"
RAINBOW = "rainbow"
GREENS = "greens"
@@ -295,51 +293,6 @@
(0,1,0), (.6,1,.6)],
"blank": [(1,1,1), (1,1,1), (1,1,1), (1,1,1)]}
- def __init__(self, app, name):
- super(PieChartPage, self).__init__(app, name)
-
- param = IntegerParameter(app, "param")
- self.slices = ListParameter(app, "slice", param)
- self.add_parameter(self.slices)
-
- self.color_scheme = Parameter(app, "cs")
- self.add_parameter(self.color_scheme)
-
- self.radius = IntegerParameter(app, "r")
- self.add_parameter(self.radius)
-
- # used to keep all the parameter names and the page name in one class
- @classmethod
- def get_href(cls, items, scheme, radius):
- page = cls.PAGE_NAME
-
- tokens = ["slice=%d" % x for x in items]
-
- tokens.append("r=%s" % radius)
-
- assert scheme in cls.color_schemes.keys()
- tokens.append("cs=%s" % scheme)
-
- src = "%s?%s" % (page, ";".join(tokens))
- return src
-
- def do_render(self, session):
- radius = self.radius.get(session)
-
- slices = self.slices.get(session)
- color_scheme = self.color_scheme.get(session)
- colors = self.color_schemes[color_scheme]
-
- pie = CuminPieChart(radius)
- surface = pie.plot_pie(slices, colors)
-
- writer = Writer()
- surface.write_to_png(writer)
- return writer.to_string()
-
- def get_content_type(self, session):
- return "image/png"
-
class StatChartPage(Page):
# handles stats.png request
def __init__(self, app, name):
@@ -465,151 +418,6 @@
max_samples = int(width * 1.5)
return max(int(duration / max_samples), 1)
- def render_samples(self, session, recent):
- c = {(1,0,0): "red", (0,0,1): "blue", (0,1,0): "green"}
- cached_samples, title_xy = self.get_cached_samples(session, recent)
- if cached_samples:
- rets = dict()
- for stat in cached_samples:
- ret = dict()
- ret["color"] = c[cached_samples[stat][1]]
- ret["points"] = cached_samples[stat][0]
- ret["xy"] = title_xy[cached_samples[stat][1]]
- rets[stat.name] = ret
- return str(rets)
-
- def do_render(self, session):
- adapter, stats = self.get_adapter_stats(session)
- colors = ((1,0,0), (0,0,1), (0,1,0))
-
- recent = None
- if len(stats):
- recent = adapter.recent()
- else:
- return
-
- # mouseover event wants the points returned in a array
- if self.samples.get(session):
- return self.render_samples(session, recent)
-
- #if recent:
- # cached_png = self.get_cached(session, recent)
- # if cached_png:
- # return cached_png
-
- samples = dict()
- values = dict()
-
- width = self.container_width.get(session)
- height = self.container_height.get(session)
- mode = self.mode.get(session)
- duration = self.duration.get(session)
- interval = self.get_interval(session, duration, width)
-
- chart = TimeSeriesChart(width, height, interval=interval)
-
- if mode == "rate":
- #method = None # don't do averaging
- method = self.method.get(session)
- for stat in stats:
- os = adapter.samples(stat, duration, interval, method)
- ns = list()
- prev = None
-
- for sample in reversed(os):
- if prev is not None:
- rate = calc_rate(float(sample[1]), float(prev[1]),
- secs(sample[0]), secs(prev[0]))
-
- ns.insert(0, (sample[0], rate, None))
-
- prev = sample
-
- samples[stat] = ns
- else:
- method = self.method.get(session)
- for stat in stats:
- samples[stat] = adapter.samples(stat, duration, interval, method)
-
- type = self.type.get(session)
- if type == "percent":
- total_property = self.total_property.get(session)
- total = self.get_object_property(session, total_property)
- total = total and float(total) or 1.0
-
- for stat in stats:
- percents = [(x[0], (float(x[1]) / total) * 100.0, x[2])
- for x in samples[stat] if x[1] is not None]
- samples[stat] = percents
-
- # take stddev into account for max and min y values
- deviated_values = list()
- for stat in stats:
- for x in samples[stat]:
- d1 = float(nvl(x[1], 0))
- d2 = float(nvl(x[2], 0) / 2)
- dv = (d1 + d2, d1 - d2)
- deviated_values.append(dv)
-
- max_value = deviated_values and max(max(deviated_values)) or 1
- min_value = deviated_values and min(min(deviated_values)) or 0
-
- # convert from decimal to float to avoid exceptions
- max_value = float(max_value)
- min_value = float(min_value)
-
- max_value = round(max_value * 1.1 + 1)
- if type == "percent" and max_value > 100:
- # since none of our percentage graphs go above 100%
- # we limit it here to match the flash graph
- max_value = 100
-
- if min_value < 0:
- min_value = round(min_value * 1.1 - 1)
-
- chart.x_max = duration
- chart.x_min = 0
- chart.y_max = max_value
- chart.y_min = min_value
-
- x_intervals = 8
- x_step = 2
-
- if chart.x_max == 600:
- x_intervals = 10
-
- y_intervals = 6
- y_step = 2
-
- if chart.y_max < 3:
- y_step = 3
-
- chart.plot_x_axis(x_intervals, x_step)
- chart.plot_y_axis(y_intervals, y_step)
-
- points = dict()
- for stat, color in zip(stats, colors):
- points[stat] = (chart.plot_values(samples[stat], color=color), color)
-
- for stat, color in zip(stats, colors):
- chart.plot_ticks(samples[stat], color=color)
-
- chart.plot_frame()
- chart.plot_interval(interval)
-
- if mode == "rate":
- titles = ["%s / sec" % x.title for x in stats]
- else:
- titles = ["%s%s" % ((type == "percent") and "Percent " or "", x.short_title and x.short_title or x.title) for x in stats]
-
- title_xy = chart.plot_legend(titles, colors)
-
- self.cache_it(session, chart, {'recent': recent, 'samples': points, "title_xy": title_xy})
-
- writer = Writer()
- chart.write(writer)
- return writer.to_string()
-
class ModifiedAgentIdParameter(StringParameter):
def get(self, session):
agent = super(ModifiedAgentIdParameter, self).get(session)
@@ -1318,140 +1126,6 @@
def chart_factory(self, chart_type):
if chart_type == "area":
chart_obj = AreaChart(self.app, chart_type, self)
- elif chart_type == "stacked":
- chart_obj = StackedAreaChart(self.app, chart_type, self)
- #chart_obj = StackedChart(self.app, chart_type, self)
- elif chart_type == "percent":
- chart_obj = PercentAreaChart(self.app, chart_type, self)
elif chart_type == "pie":
chart_obj = FlashPieChart(self.app, chart_type, self)
-
return chart_obj
-
-class PercentAreaChart(AreaChart):
- def get_max_min(self, session, stats, samples, time_span, end_seconds_ago):
- max_val, min_val = super(PercentAreaChart, self).get_max_min(session, stats, samples, time_span, end_seconds_ago)
-
- percent = self.page.percent_property.get(session)
- total = self.page.get_object_property(session, percent)
- total = total and float(total) or 1.0
-
- max_val = (max_val / total) * 100.0
- min_val = (min_val / total) * 100.0
-
- max_val = round(max_val * 1.1 + 1)
- # cap at 100
- max_val = min(max_val, 100.0)
-
- if min_val < 0:
- min_val = round(min_val * 1.1 - 1)
-
- return max_val, min_val
-
- def get_vals(self, session, samples, stat, text, duration, end_secs):
- tnow = time()
- vals = list()
- percent = self.page.percent_property.get(session)
- total = self.page.get_object_property(session, percent)
-
- min_dt = tnow - duration - end_secs
- for dt, value, dev in samples[stat]:
- if value is not None:
- if total is None or total == 0.0:
- vals.append({"dt": secs(dt), "y": 0.0})
- else:
- vals.append({"dt": secs(dt), "y": (float(value) / float(total)) * 100.0})
- if secs(dt) < min_dt:
- break
-
- vals.reverse()
- return vals
-
- def get_line_title(self, stat):
- return "Percent %s" % stat.title
-
-class StatStackedPage(StatChartPage):
- # handles stacked.png requests
- def do_render(self, session):
- adapter, stats = self.get_adapter_stats(session)
-
- if len(stats):
- recent = adapter.recent()
- if recent:
- cached_png = self.get_cached(session, recent)
- if cached_png:
- return cached_png
-
- legend_height = len(stats) * 16 + 16
-
- width = self.container_width.get(session)
- height = self.container_height.get(session)
- chart = StackedValueChart(width, height, legend_height)
-
- duration = self.duration.get(session)
- method = self.method.get(session)
- interval = self.get_interval(session, duration, width)
-
- max_value = 1
- min_value = 999999
-
- points = dict()
- samples = dict()
- collapsed = dict()
- values = dict()
- for stat in stats:
- samples[stat] = adapter.samples(stat, duration, interval, method)
- # we sometimes get multiple samples for the same qmf_update_time
- for sample in samples[stat]:
- collapsed[sample[0]] = sample[1]
-
- for t in collapsed:
- if not t in points:
- points[t] = list()
- values[t] = 0
- points[t].append(collapsed[t])
- values[t] = values[t] + collapsed[t]
- max_value = max(values[t], max_value)
- min_value = min(values[t], min_value)
-
- max_value = round(max_value * 1.1 + 1)
-
- if min_value < 0:
- min_value = round(min_value * 1.1 - 1)
-
- chart.x_max = duration
- chart.x_min = 0
- chart.y_max = max_value
- chart.y_min = min_value
-
- x_intervals = 8
- x_step = 2
-
- if chart.x_max == 600:
- x_intervals = 10
-
- y_intervals = 6
- y_step = 2
-
- if chart.y_max < 3:
- y_step = 3
-
- chart.plot_x_axis(x_intervals, x_step)
- chart.plot_y_axis(y_intervals, y_step)
-
- colors = ((1,0,0), (0,0,1), (0,1,0), (1,0,1), (1,1,0), (0,1,1), (0,0,0))
-
- for t in points:
- chart.plot_values(t, points[t], colors)
-
- chart.plot_frame()
-
- titles = [x.title for x in stats]
-
- chart.plot_legend(reversed(titles), reversed(colors[:len(titles)]))
-
- self.cache_it(session, chart, {'recent': recent, 'samples': None, "title_xy": None})
-
- writer = Writer()
- chart.write(writer)
- return writer.to_string()
12 years, 6 months
r5127 - in trunk/cumin: bin python/cumin
by tmckay@fedoraproject.org
Author: tmckay
Date: 2011-11-09 20:30:18 +0000 (Wed, 09 Nov 2011)
New Revision: 5127
Modified:
trunk/cumin/bin/cumin-admin
trunk/cumin/bin/cumin-data
trunk/cumin/bin/cumin-web
trunk/cumin/python/cumin/admin.py
Log:
Tweaks to error checking after testing latest commits
Modified: trunk/cumin/bin/cumin-admin
===================================================================
--- trunk/cumin/bin/cumin-admin 2011-11-09 19:36:31 UTC (rev 5126)
+++ trunk/cumin/bin/cumin-admin 2011-11-09 20:30:18 UTC (rev 5127)
@@ -6,7 +6,7 @@
import subprocess
from subprocess import PIPE
-from psycopg2 import IntegrityError, OperationalError
+from psycopg2 import IntegrityError, OperationalError, ProgrammingError
home = os.environ.get("CUMIN_HOME", os.path.normpath("/usr/share/cumin"))
sys.path.append(os.path.join(home, "python"))
@@ -232,8 +232,8 @@
print "This version of cumin-admin can upgrade the schema to version %s" % target
print "The schema version is already %s" % curr
print "Have you been using a newer version of cumin?"
- print "In order to use this version of cumin you will have to recreate the schema"
-
+ print "You will have to recreate the schema with "\
+ "'cumin-admin drop-schema' and 'cumin-admin create-schema'"
else:
print "Attempting to upgrade the schema from %s to %s" % (curr, target)
upgrade_dir = os.path.join(app.home, "model/upgrades")
@@ -242,6 +242,8 @@
if not upgrade_path:
print "Could not find an upgrade path from %s to %s in %s" % \
(curr, target, upgrade_dir)
+ print "You will have to recreate the schema with "\
+ "'cumin-admin drop-schema' and 'cumin-admin create-schema'"
else:
if not confirm("Found an update path. Alter the schema?", True):
@@ -272,7 +274,10 @@
print "Upgrade to schema version %s succeeded" % target
def handle_create_schema(app, cursor, opts, args):
- app.admin.create_schema(cursor)
+ try:
+ app.admin.create_schema(cursor)
+ except ProgrammingError:
+ error("The schema already exists")
app.admin.add_role(cursor, "user")
app.admin.add_role(cursor, "admin")
@@ -284,9 +289,9 @@
schema_version = app.admin.check_schema(cursor)
except SchemaMissing:
error("The schema is missing, run 'cumin-admin create-schema'")
- except Exception, e:
- error(str(e))
-
+ except SchemaVersion, e:
+ error(str(e) + ", run 'cumin-admin upgrade-schema'")
+
print "The schema is OK (schema version %s)" % schema_version
def handle_drop_schema(app, cursor, opts, args):
Modified: trunk/cumin/bin/cumin-data
===================================================================
--- trunk/cumin/bin/cumin-data 2011-11-09 19:36:31 UTC (rev 5126)
+++ trunk/cumin/bin/cumin-data 2011-11-09 20:30:18 UTC (rev 5127)
@@ -148,9 +148,6 @@
# Get options
opts, args = parser.parse_args()
- if len(args) != 0:
- log.error("Extra arguments:" + "".join([" "+arg for arg in args]))
- raise EarlyReturn
# --section controls which section is read from the config file
# If a section other than "data" is specified, require it to exist
@@ -167,6 +164,10 @@
values.log_max_mb,
values.log_max_archives)
+ if len(args) != 0:
+ log.error("Extra arguments:" + "".join([" "+arg for arg in args]))
+ raise EarlyReturn
+
model_dir = os.path.join(config.home, "model")
broker_uris = [x.strip() for x in opts.brokers.split(",")]
@@ -232,13 +233,11 @@
except KeyboardInterrupt:
log.info("Received SIGINT")
- except SystemExit:
+ except (SystemExit, EarlyReturn):
if "--help" not in sys.argv:
+ log.error("Error in options, arguments, or config values")
return_code = 1
- except EarlyReturn:
- return_code = 1
-
except OperationalError:
# Failed to talk to the database on check()
log.info("Run 'cumin-database check' as root for more information.")
Modified: trunk/cumin/bin/cumin-web
===================================================================
--- trunk/cumin/bin/cumin-web 2011-11-09 19:36:31 UTC (rev 5126)
+++ trunk/cumin/bin/cumin-web 2011-11-09 20:30:18 UTC (rev 5127)
@@ -103,9 +103,6 @@
# Get options
opts, args = parser.parse_args()
- if len(args) != 0:
- log.error("Extra arguments:" + "".join([" "+arg for arg in args]))
- raise EarlyReturn
# --section controls which section is read from the config file
# If a section other than "web" is specified, require it to exist
@@ -122,6 +119,10 @@
values.log_max_mb,
values.log_max_archives)
+ if len(args) != 0:
+ log.error("Extra arguments:" + "".join([" "+arg for arg in args]))
+ raise EarlyReturn
+
broker_uris = [x.strip() for x in opts.brokers.split(",")]
authmech = [x.strip() for x in values.auth.split(";")]
cumin = Cumin(config.get_home(), broker_uris, opts.database,
@@ -165,8 +166,9 @@
log.info("Received SIGINT")
pass
- except SystemExit:
+ except (SystemExit, EarlyReturn):
if "--help" not in sys.argv:
+ log.error("Error in options, arguments, or config values")
return_code = 1
except EarlyReturn:
Modified: trunk/cumin/python/cumin/admin.py
===================================================================
--- trunk/cumin/python/cumin/admin.py 2011-11-09 19:36:31 UTC (rev 5126)
+++ trunk/cumin/python/cumin/admin.py 2011-11-09 20:30:18 UTC (rev 5127)
@@ -64,7 +64,7 @@
if info.schema_version != schema_version:
args = (schema_version, info.schema_version)
- msg = "Expected schema version %s; found version %s" % args
+ msg = "Expected schema version %s, found version %s" % args
raise SchemaVersion(msg)
return info.schema_version
12 years, 6 months
r5126 - in trunk: cumin/bin cumin/python/cumin mint/python/mint
by tmckay@fedoraproject.org
Author: tmckay
Date: 2011-11-09 19:36:31 +0000 (Wed, 09 Nov 2011)
New Revision: 5126
Modified:
trunk/cumin/bin/cumin
trunk/cumin/bin/cumin-admin
trunk/cumin/bin/cumin-data
trunk/cumin/bin/cumin-database
trunk/cumin/bin/cumin-web
trunk/cumin/python/cumin/admin.py
trunk/cumin/python/cumin/database.py
trunk/cumin/python/cumin/main.py
trunk/mint/python/mint/database.py
trunk/mint/python/mint/main.py
Log:
Incorporate environment checks from sysvinit into the cumin executables.
Cumin-web, cumin-data and cumin-admin will now check to make sure the
database is installed and running and that the schema version is correct.
Improved logging and error reporting in cumin executables.
Change cumin-database to refer users to 'cumin-database install' in most
case where the environment is not correct. Install will appropriately
fix most issues.
Modified: trunk/cumin/bin/cumin
===================================================================
--- trunk/cumin/bin/cumin 2011-11-09 19:32:49 UTC (rev 5125)
+++ trunk/cumin/bin/cumin 2011-11-09 19:36:31 UTC (rev 5126)
@@ -146,8 +146,7 @@
for app in apps:
poll = app[PROCESS] and app[PROCESS].poll()
if poll is not None:
- log.warn("Subprocess exited (pid %s), status %s" %\
- (app[PROCESS].pid, str(poll)))
+
# If the low bit is set on the return code, the
# process got an error during init checks.
# Exit and shut down any processes that have already
@@ -155,17 +154,23 @@
# Note, signals that cause termination will result in
# a negative error code, we treat those as "normal"
if poll > 0 and poll & 1:
- log.error("Subprocess failed init checks (pid %s),"\
- " stopping cumin" % app[PROCESS].pid)
+ log.error("Subprocess failed init checks (pid %s), "\
+ "status %s, check subprocess logs for details" %\
+ (app[PROCESS].pid, str(poll)))
+ log.info("Stopping cumin")
app[PROCESS] = None
return_code = 2
complete = len(apps)
break
- elif options.init_only:
- app[PROCESS] = None
- complete += 1
else:
- start(app, "Restart")
+ log.warn("Subprocess exited (pid %s), status %s, "\
+ "check subprocess logs for details" %\
+ (app[PROCESS].pid, str(poll)))
+ if options.init_only:
+ app[PROCESS] = None
+ complete += 1
+ else:
+ start(app, "Restart")
finally:
# Try a ctrl-C first
log.info("Send SIGINT to all children")
Modified: trunk/cumin/bin/cumin-admin
===================================================================
--- trunk/cumin/bin/cumin-admin 2011-11-09 19:32:49 UTC (rev 5125)
+++ trunk/cumin/bin/cumin-admin 2011-11-09 19:36:31 UTC (rev 5126)
@@ -6,7 +6,7 @@
import subprocess
from subprocess import PIPE
-from psycopg2 import IntegrityError
+from psycopg2 import IntegrityError, OperationalError
home = os.environ.get("CUMIN_HOME", os.path.normpath("/usr/share/cumin"))
sys.path.append(os.path.join(home, "python"))
@@ -16,6 +16,7 @@
from cumin import *
from cumin.config import *
from cumin.util import *
+from cumin.admin import SchemaMissing
def main():
uid = os.getuid()
@@ -70,14 +71,41 @@
app = Cumin(config.get_home(), broker_uris, opts.database, authmech=authmech)
app.check()
- app.init()
+ # Normally, a schema version check during Cumin init will raise
+ # an exception if the schema version doesn't match. However,
+ # cumin-admin is the mechanism for fixing the schema so we
+ # have to avoid the check here!
+ try:
+ app.init(schema_version_check=False)
+ except OperationalError:
+ print "Can't talk to the database"
+ error("Run 'cumin-database check' as root for more information")
+
conn = app.database.get_connection()
cursor = conn.cursor()
+
+ # Okay, do the schema version check here and disallow
+ # all but schema commands if the version is wrong
+ if name not in ["check_schema",
+ "create_schema",
+ "drop_schema",
+ "print_schema",
+ "upgrade_schema"]:
+ err = True
+ try:
+ app.admin.check_schema(cursor)
+ err = False
+ except SchemaMissing:
+ print("The schema is missing, run 'cumin-admin create-schema'")
+ except SchemaVersion, e:
+ print str(e)
+ print("Run 'cumin-admin upgrade-schema'")
+ if err:
+ error("Only schema commands are allowed until the schema is repaired")
try:
handler(app, cursor, opts, args[1:])
-
conn.commit()
finally:
cursor.close()
@@ -191,7 +219,11 @@
print app.admin.get_schema(),
def handle_upgrade_schema(app, cursor, opts, args):
- curr = app.admin.get_schema_version(cursor)
+ try:
+ curr = app.admin.get_schema_version(cursor)
+ except SchemaMissing:
+ error("The schema is missing, run 'cumin-admin create-schema'")
+
target = app.admin.get_target_schema_version()
if curr == target:
print "The schema is already version %s, nothing to do" % target
@@ -250,16 +282,20 @@
def handle_check_schema(app, cursor, opts, args):
try:
schema_version = app.admin.check_schema(cursor)
+ except SchemaMissing:
+ error("The schema is missing, run 'cumin-admin create-schema'")
except Exception, e:
error(str(e))
print "The schema is OK (schema version %s)" % schema_version
def handle_drop_schema(app, cursor, opts, args):
- app.admin.drop_schema(cursor)
+ try:
+ app.admin.drop_schema(cursor)
+ print "The schema is dropped"
+ except SchemaMissing:
+ print "The schema has already been dropped"
- print "The schema is dropped"
-
def get_users(app, cursor):
user_cls = app.model.com_redhat_cumin.User
role_cls = app.model.com_redhat_cumin.Role
Modified: trunk/cumin/bin/cumin-data
===================================================================
--- trunk/cumin/bin/cumin-data 2011-11-09 19:32:49 UTC (rev 5125)
+++ trunk/cumin/bin/cumin-data 2011-11-09 19:36:31 UTC (rev 5126)
@@ -10,6 +10,8 @@
from cumin.util import *
from mint import *
from parsley.loggingex import PipeLogThread
+from psycopg2 import OperationalError
+from cumin.admin import SchemaVersion, SchemaMissing
def restore_IO():
sys.stderr = sys.__stderr__
@@ -228,7 +230,7 @@
sleep(86400)
except KeyboardInterrupt:
- pass
+ log.info("Received SIGINT")
except SystemExit:
if "--help" not in sys.argv:
@@ -237,6 +239,19 @@
except EarlyReturn:
return_code = 1
+ except OperationalError:
+ # Failed to talk to the database on check()
+ log.info("Run 'cumin-database check' as root for more information.")
+ return_code = 3
+
+ except SchemaMissing:
+ log.info("Run 'cumin-admin create-schema' as root")
+ return_code = 4
+
+ except SchemaVersion:
+ log.info("Run 'cumin-admin upgrade-schema' as root")
+ return_code = 5
+
except:
print_exc()
return_code = 2
Modified: trunk/cumin/bin/cumin-database
===================================================================
--- trunk/cumin/bin/cumin-database 2011-11-09 19:32:49 UTC (rev 5125)
+++ trunk/cumin/bin/cumin-database 2011-11-09 19:36:31 UTC (rev 5126)
@@ -73,7 +73,7 @@
if [[ ! -f "$pghbaconf" ]]; then
echo "Error: The database is not initialized"
if [ "$1" != noadvice ]; then
- echo "Hint: Run 'cumin-database initialize'"
+ echo "Hint: Run 'cumin-database install'"
fi
return 1
fi
@@ -83,7 +83,7 @@
grep "$dbname" "$pghbaconf" &> /dev/null || {
echo "Error: The database is not configured"
if [ "$1" != noadvice ]; then
- echo "Hint: Run 'cumin-database configure'"
+ echo "Hint: Run 'cumin-database install'"
fi
return 1
}
@@ -93,7 +93,7 @@
psql -d cumin -U cumin -h localhost -c '\q' &> /dev/null || {
echo "Error: The database is not created"
if [ "$1" != noadvice ]; then
- echo "Hint: Run 'cumin-database create'"
+ echo "Hint: Run 'cumin-database install'"
fi
return 1
}
@@ -117,7 +117,7 @@
*)
echo "Error: The database is not created"
if [ "$1" != noadvice ]; then
- echo "Hint: Run 'cumin-database create'"
+ echo "Hint: Run 'cumin-database install'"
fi
return 1
;;
@@ -132,7 +132,7 @@
WARNING
This script installs a cumin database into the system postgresql
-instance.
+instance. It will take the following actions as necessary.
* It will stop and start the postgresql service.
Modified: trunk/cumin/bin/cumin-web
===================================================================
--- trunk/cumin/bin/cumin-web 2011-11-09 19:32:49 UTC (rev 5125)
+++ trunk/cumin/bin/cumin-web 2011-11-09 19:36:31 UTC (rev 5126)
@@ -9,6 +9,8 @@
from cumin.config import *
from cumin.util import *
from parsley.loggingex import PipeLogThread
+from psycopg2 import OperationalError
+from cumin.admin import SchemaVersion, SchemaMissing
def restore_IO():
sys.stderr = sys.__stderr__
@@ -160,6 +162,7 @@
break
except KeyboardInterrupt:
+ log.info("Received SIGINT")
pass
except SystemExit:
@@ -169,6 +172,19 @@
except EarlyReturn:
return_code = 1
+ except OperationalError:
+ # Failed to talk to the database on check()
+ log.info("Run 'cumin-database check' as root for more information.")
+ return_code = 3
+
+ except SchemaMissing:
+ log.info("Run 'cumin-admin create-schema' as root")
+ return_code = 4
+
+ except SchemaVersion:
+ log.info("Run 'cumin-admin upgrade-schema' as root")
+ return_code = 5
+
except:
print_exc()
return_code = 2
Modified: trunk/cumin/python/cumin/admin.py
===================================================================
--- trunk/cumin/python/cumin/admin.py 2011-11-09 19:32:49 UTC (rev 5125)
+++ trunk/cumin/python/cumin/admin.py 2011-11-09 19:36:31 UTC (rev 5126)
@@ -1,12 +1,18 @@
from StringIO import StringIO
from util import *
-from psycopg2 import IntegrityError
+from psycopg2 import IntegrityError, ProgrammingError
log = logging.getLogger("cumin.admin")
schema_version = "1.1"
+class SchemaMissing(Exception):
+ pass
+
+class SchemaVersion(Exception):
+ pass
+
class CuminAdmin(object):
def __init__(self, app):
self.app = app
@@ -34,9 +40,13 @@
def get_schema_version(self, cursor):
cls = self.app.model.com_redhat_cumin.Info
- info = cls.get_object(cursor)
+ try:
+ info = cls.get_object(cursor)
+ except ProgrammingError:
+ info = None
+
if not info:
- raise Exception("The schema isn't there")
+ raise SchemaMissing("The schema isn't there")
return info.schema_version
def get_target_schema_version(self):
@@ -44,19 +54,28 @@
def check_schema(self, cursor):
cls = self.app.model.com_redhat_cumin.Info
- info = cls.get_object(cursor)
+ try:
+ info = cls.get_object(cursor)
+ except ProgrammingError:
+ info = None
if not info:
- raise Exception("The schema isn't there")
+ raise SchemaMissing("The schema isn't there")
if info.schema_version != schema_version:
args = (schema_version, info.schema_version)
msg = "Expected schema version %s; found version %s" % args
- raise Exception(msg)
+ raise SchemaVersion(msg)
return info.schema_version
def drop_schema(self, cursor):
+ cls = self.app.model.com_redhat_cumin.Info
+ try:
+ info = cls.get_object(cursor)
+ except ProgrammingError:
+ raise SchemaMissing("The schema isn't there")
+
writer = StringIO()
self.app.model.sql_model.write_drop_ddl(writer)
sql = writer.getvalue()
Modified: trunk/cumin/python/cumin/database.py
===================================================================
--- trunk/cumin/python/cumin/database.py 2011-11-09 19:32:49 UTC (rev 5125)
+++ trunk/cumin/python/cumin/database.py 2011-11-09 19:36:31 UTC (rev 5126)
@@ -16,11 +16,37 @@
self.connection_args = dict()
self.thread_local = threading.local()
- def init(self):
+ def init(self, schema_version_check):
log.info("Initializing %s", self)
#m = re.match(r"^([^:]+)://([^@]+)@([^/]+)/(.+)$", self.uri)
+ conn = None
+ try:
+ conn = self.get_connection()
+ cursor = conn.cursor()
+ self.check_connection(cursor)
+ if schema_version_check:
+ self.app.admin.check_schema(cursor)
+ conn.close()
+ except psycopg2.OperationalError:
+ conn and conn.close()
+ log.error("Connection to database failed, is the database running?")
+ raise
+ except Exception, e:
+ conn and conn.close()
+ log.error(str(e))
+ raise
+ def check(self):
+ # checks moved to init because the model has to be
+ # initialized before we can check the schema. And
+ # there is no point connecting to the database twice...
+ log.info("Checking %s", self)
+
+ def check_connection(self, cursor):
+ cursor.execute("select now()")
+ log.debug("Database is talking at '%s'", self.dsn)
+
def get_connection(self):
return psycopg2.connect(self.dsn)
Modified: trunk/cumin/python/cumin/main.py
===================================================================
--- trunk/cumin/python/cumin/main.py 2011-11-09 19:32:49 UTC (rev 5125)
+++ trunk/cumin/python/cumin/main.py 2011-11-09 19:36:31 UTC (rev 5126)
@@ -111,6 +111,7 @@
raise Exception(msg % self.home)
self.model.check()
+ self.database.check()
def _init_grid_persona(self):
self.main_page = GridMainPage(self, "index.html")
@@ -163,7 +164,7 @@
inventory.Module(self, "inventory")
usergrid.Module(self, "usergrid")
- def init(self):
+ def init(self, schema_version_check=True):
log.info("Initializing %s", self)
# Create RPC interfaces for QMF and aviary.
@@ -216,7 +217,7 @@
self.model.init()
self.session.init()
- self.database.init()
+ self.database.init(schema_version_check)
self.server.init()
# Create the correct persona
Modified: trunk/mint/python/mint/database.py
===================================================================
--- trunk/mint/python/mint/database.py 2011-11-09 19:32:49 UTC (rev 5125)
+++ trunk/mint/python/mint/database.py 2011-11-09 19:36:31 UTC (rev 5126)
@@ -14,22 +14,31 @@
def check(self):
log.info("Checking %s", self)
+ # checks moved to init because the model has to be
+ # initialized before we can check the schema. And
+ # there is no point connecting to the database twice...
- self.check_connection()
-
def init(self):
log.info("Initializing %s", self)
-
- def check_connection(self):
- conn = self.get_connection()
-
+ conn = None
try:
+ conn = self.get_connection()
cursor = conn.cursor()
- cursor.execute("select now()")
-
- log.debug("Database is talking at '%s'", self.dsn)
- finally:
+ self.check_connection(cursor)
+ self.app.admin.check_schema(cursor)
conn.close()
+ except psycopg2.OperationalError:
+ conn and conn.close()
+ log.error("Connection to database failed, is the database running?")
+ raise
+ except Exception, e:
+ conn and conn.close()
+ log.error(str(e))
+ raise
+ def check_connection(self, cursor):
+ cursor.execute("select now()")
+ log.debug("Database is talking at '%s'", self.dsn)
+
def __repr__(self):
return self.__class__.__name__
Modified: trunk/mint/python/mint/main.py
===================================================================
--- trunk/mint/python/mint/main.py 2011-11-09 19:32:49 UTC (rev 5125)
+++ trunk/mint/python/mint/main.py 2011-11-09 19:36:31 UTC (rev 5126)
@@ -4,7 +4,7 @@
from session import MintSession
from update import UpdateThread
from vacuum import VacuumThread
-
+from cumin.admin import *
from util import *
log = logging.getLogger("mint.main")
@@ -16,7 +16,7 @@
self.session = MintSession(self, broker_uris)
self.database = MintDatabase(self, database_dsn)
-
+ self.admin = CuminAdmin(self)
self.update_thread = UpdateThread(self)
self.expire_enabled = True
12 years, 6 months
r5125 - branches/noflash/cumin/python/cumin/messaging
by croberts@fedoraproject.org
Author: croberts
Date: 2011-11-09 19:32:49 +0000 (Wed, 09 Nov 2011)
New Revision: 5125
Modified:
branches/noflash/cumin/python/cumin/messaging/queue.py
Log:
Correcting spelling error (eequeued becomes dequeued)
Modified: branches/noflash/cumin/python/cumin/messaging/queue.py
===================================================================
--- branches/noflash/cumin/python/cumin/messaging/queue.py 2011-11-09 15:25:04 UTC (rev 5124)
+++ branches/noflash/cumin/python/cumin/messaging/queue.py 2011-11-09 19:32:49 UTC (rev 5125)
@@ -483,7 +483,7 @@
class EnqueueDequeueRateChart(StatFlashChart):
def render_title(self, session):
- return "Durable messages enqueued and eequeued"
+ return "Durable messages enqueued and dequeued"
class JournalStats(StatSet):
def __init__(self, app, name, queue):
12 years, 6 months