apache/bodhi.conf | 2 -
bodhi.spec | 2 -
bodhi/buildsys.py | 14 +++++--
bodhi/config/app.cfg | 5 ++
bodhi/controllers.py | 2 -
bodhi/jobs.py | 17 ++++++--
bodhi/mail.py | 2 -
bodhi/metrics.py | 84 ++++++++++++++++++++++++++++++++++----------
bodhi/model.py | 20 ++--------
bodhi/templates/welcome.kid | 4 +-
10 files changed, 105 insertions(+), 47 deletions(-)
New commits:
commit 69a5877a990365513732157873e981b5a8d39ddc
Author: Luke Macken <lmacken(a)redhat.com>
Date: Thu Aug 14 01:31:12 2008 -0400
Support the new fas User properties, as well as the default turbogears identity
providers.
diff --git a/bodhi/templates/welcome.kid b/bodhi/templates/welcome.kid
index 018c2be..d162220 100644
--- a/bodhi/templates/welcome.kid
+++ b/bodhi/templates/welcome.kid
@@ -26,7 +26,7 @@
<body>
<table width="90%" align="center" valign="top">
<tr>
- <td align="left"
valign="bottom"><b><font size="4">Welcome to bodhi
v${version}<span py:if="not tg.identity.anonymous">,
${tg.identity.user.display_name.split()[0]}</span></font></b></td>
+ <td align="left"
valign="bottom"><b><font size="4">Welcome to bodhi
v${version}<span py:if="not tg.identity.anonymous">,
${hasattr(tg.identity.user, 'human_name') and
tg.identity.user.human_name.split()[0] or
tg.identity.user.display_name}</span></font></b></td>
<td align="right">
<table>
<tr>
@@ -75,7 +75,7 @@
<tr>
<td>
<span py:if="updates">
- <h3><span py:replace="tg.identity.anonymous and
'Latest' or '%s\'' % tg.identity.user.user_name"></span>
Updates</h3>
+ <h3><span py:replace="tg.identity.anonymous and
'Latest' or '%s\'' % (hasattr(tg.identity, 'user_name') and
tg.identity.user_name or tg.identity.user.user_name)"></span>
Updates</h3>
${updates.display()}
</span>
</td>
commit 976fac2cd6cc2d3722a214ddab2bdc431bf8d24a
Author: Luke Macken <lmacken(a)redhat.com>
Date: Thu Aug 14 01:30:31 2008 -0400
s/sortBy/orderBy/
diff --git a/bodhi/controllers.py b/bodhi/controllers.py
index 8e183bd..96f2db0 100644
--- a/bodhi/controllers.py
+++ b/bodhi/controllers.py
@@ -998,7 +998,7 @@ class Root(controllers.RootController):
AND(PackageUpdate.q.type == 'security',
PackageUpdate.q.status == 'pending',
PackageUpdate.q.approved == None),
- sortBy=PackageUpdate.q.date_submitted)
+ orderBy=PackageUpdate.q.date_submitted)
return dict(updates=updates)
@expose(template="bodhi.templates.user")
commit 87eac516a14db4f79e09704c6e04b603afb53e4d
Author: Luke Macken <lmacken(a)redhat.com>
Date: Thu Aug 14 01:30:04 2008 -0400
Spec bump
diff --git a/bodhi.spec b/bodhi.spec
index e72bc40..27fcf6c 100644
--- a/bodhi.spec
+++ b/bodhi.spec
@@ -3,7 +3,7 @@
Name: bodhi
Version: 0.5.0
-Release: 1%{?dist}
+Release: 6%{?dist}
Summary: A modular framework that facilitates publishing software updates
Group: Applications/Internet
License: GPLv2+
commit 91a1d6c2bd4a020cc16a3765149ddff4f6497261
Author: Luke Macken <lmacken(a)redhat.com>
Date: Thu Aug 14 00:11:14 2008 -0400
Stop trying to email anonymous commenters
diff --git a/bodhi/model.py b/bodhi/model.py
index 9d3d057..23694cf 100644
--- a/bodhi/model.py
+++ b/bodhi/model.py
@@ -617,7 +617,7 @@ class PackageUpdate(SQLObject):
for person in self.get_maintainers():
people.add(person)
for comment in self.comments:
- if comment.author == 'bodhi':
+ if comment.anonymous or comment.author == 'bodhi':
continue
people.add(comment.author)
mail.send(people, 'comment', self)
commit 742ec2d3771f2126fa6f61bf13e21512b11ac75c
Author: Luke Macken <lmacken(a)redhat.com>
Date: Wed Aug 13 23:56:15 2008 -0400
Stop logging the fully text to every email we send.
diff --git a/bodhi/mail.py b/bodhi/mail.py
index ea3c11f..50d5ee9 100644
--- a/bodhi/mail.py
+++ b/bodhi/mail.py
@@ -368,8 +368,8 @@ def send_mail(sender, to, subject, body):
message = turbomail.Message(sender, to, subject)
message.plain = body
try:
+ #log.debug("Sending mail: %s" % message.plain)
turbomail.enqueue(message)
- log.debug("Sending mail: %s" % message.plain)
except MailNotEnabledException:
log.warning("TurboMail is not enabled!")
except Exception, e:
commit b3f28387e398ed26b5f9e1453f4bdee5d4007d67
Author: Luke Macken <lmacken(a)redhat.com>
Date: Wed Aug 13 19:57:48 2008 -0400
Make our certificates configurable
diff --git a/bodhi/buildsys.py b/bodhi/buildsys.py
index c8a25ff..46deb5b 100644
--- a/bodhi/buildsys.py
+++ b/bodhi/buildsys.py
@@ -154,12 +154,20 @@ class DevBuildsys(Buildsystem):
return [self.getBuild(),]
-def koji_login(client=join(expanduser('~'), '.fedora.cert'),
- clientca=join(expanduser('~'), '.fedora-upload-ca.cert'),
- serverca=join(expanduser('~'),
'.fedora-server-ca.cert')):
+def koji_login(client=None, clientca=None, serverca=None):
"""
Login to Koji and return the session
"""
+ if not client:
+ client = config.get('client_cert',
+ join(expanduser('~'), '.fedora.cert'))
+ if not clientca:
+ clientca = config.get('clientca_cert',
+ join(expanduser('~'), '.fedora-upload-ca.cert'))
+ if not serverca:
+ serverca = config.get('serverca_cert',
+ join(expanduser('~'), '.fedora-server-ca.cert'))
+
koji_session = koji.ClientSession(config.get('koji_hub'), {})
koji_session.ssl_login(client, clientca, serverca)
return koji_session
diff --git a/bodhi/config/app.cfg b/bodhi/config/app.cfg
index 41f32cd..d4903eb 100644
--- a/bodhi/config/app.cfg
+++ b/bodhi/config/app.cfg
@@ -100,6 +100,11 @@ build_dir = '%(top_level_dir)s/../packages'
# Koji's XML-RPC hub
koji_hub = 'https://koji.fedoraproject.org/kojihub'
+# Koji certs
+client_cert = None
+clientca_cert = None
+serverca_cert = None
+
##
## ACL system
## Choices are 'pkgdb', which will send a JSON query to the pkgdb_url below,
commit 49f2773f0861306cd8724ec629570fbff83db571
Author: Luke Macken <lmacken(a)redhat.com>
Date: Wed Aug 13 19:35:19 2008 -0400
Don't delay the release caching job
diff --git a/bodhi/jobs.py b/bodhi/jobs.py
index 9b98ed0..8501df4 100644
--- a/bodhi/jobs.py
+++ b/bodhi/jobs.py
@@ -170,7 +170,7 @@ def schedule():
log.debug("Scheduling cache_release_data job")
scheduler.add_interval_task(action=cache_release_data,
taskname='Cache release data',
- initialdelay=300,
+ initialdelay=0,
interval=172800)
# If we're the masher, then handle the costly metric regenration
commit eb548e5620122ca1fe14e39aa50501ed3de2625a
Author: Luke Macken <lmacken(a)redhat.com>
Date: Tue Aug 12 12:39:37 2008 -0400
Fix a few more bugs in the metrics module
diff --git a/bodhi/metrics.py b/bodhi/metrics.py
index 2ef631e..6d780b7 100644
--- a/bodhi/metrics.py
+++ b/bodhi/metrics.py
@@ -147,7 +147,7 @@ class MostUpdatedMetric(Metric):
A metric that calculates what packages have been updated the most.
"""
def __init__(self, release):
- self.release = release.long_name
+ self.release = release
self.data = {}
self.pkgs = []
@@ -191,7 +191,7 @@ class ActiveDevsMetric(Metric):
A metric that calculates which developers have pushed out the most updates
"""
def __init__(self, release):
- self.release = release.long_name
+ self.release = release
self.users = {} # { user : # updates }
self.data = {}
@@ -234,7 +234,7 @@ class KarmaMetric(Metric):
"""
def __init__(self, release):
self.data = {} # { pkg : karma }
- self.release = release.long_name
+ self.release = release
self.bestpkgs = {}
self.bestdata = []
self.worstpkgs = {}
@@ -280,7 +280,7 @@ class TopTestersMetric(Metric):
testing feedback for updates
"""
def __init__(self, release):
- self.release = release.long_name
+ self.release = release
self.data = {} # { person : # of comments }
self.people = {}
@@ -325,7 +325,7 @@ class MostTestedMetric(Metric):
A metric that calculates the packages with the most +1/-1 comments
"""
def __init__(self, release):
- self.release = release.long_name
+ self.release = release
self.data = {} # {pkg: # of +1/-1's}
self.tested_data = []
self.tested_pkgs = {}
@@ -359,7 +359,7 @@ class MostTestedMetric(Metric):
{
'xaxis': {'ticks': data['pkgs']}
},
- label = 'Most tested %s packages' % self.release
+ label = 'Most tested %s packages' % self.release.long_name
)
@@ -428,7 +428,6 @@ class MetricData(Singleton):
if not rel.metrics:
log.warning("No metrics found for %s" % rel.name)
return
- #self.init_metrics(rel) # Really?
if not freshwidgets.has_key(rel.name):
freshwidgets[rel.name] = {}
for metric in self.metrics:
commit 723a9fd3970d51fea2f2e859d08e4fc2ed9433fa
Author: Luke Macken <lmacken(a)redhat.com>
Date: Tue Aug 12 12:07:43 2008 -0400
Run the cache_release_data job every couple of days
diff --git a/bodhi/jobs.py b/bodhi/jobs.py
index 065e994..9b98ed0 100644
--- a/bodhi/jobs.py
+++ b/bodhi/jobs.py
@@ -171,7 +171,7 @@ def schedule():
scheduler.add_interval_task(action=cache_release_data,
taskname='Cache release data',
initialdelay=300,
- interval=60)
+ interval=172800)
# If we're the masher, then handle the costly metric regenration
if not config.get('masher'):
commit f0ceeacecaf55c3d5c206076ee03b27907a80f84
Author: Luke Macken <lmacken(a)redhat.com>
Date: Tue Aug 12 12:07:16 2008 -0400
Metrics optimizations
- Instead of each bodhi node calculating release stats for the sidebar on its
own, add a new metric for this data and have the masher calculate this hourly.
The results are then stored in Release.metrics['UpdateTypeMetric'], which
is then cached by our frontend bodhi instances every day.
diff --git a/bodhi/jobs.py b/bodhi/jobs.py
index 548c759..065e994 100644
--- a/bodhi/jobs.py
+++ b/bodhi/jobs.py
@@ -118,16 +118,23 @@ def cache_release_data():
for each visit (as much as possible).
"""
+ log.info("Caching release metrics")
from bodhi.model import Releases
- Releases().update()
+ try:
+ Releases().update()
+ except Exception, e:
+ log.exception(e)
+ log.info("Release cache complete")
+
def refresh_metrics():
""" Refresh all of our graphs and metrics """
- log.info("Regenerating update metrics...")
from bodhi.metrics import MetricData
- MetricData().refresh()
- log.info("Regeneration of metrics complete")
+ try:
+ MetricData().refresh()
+ except Exception, e:
+ log.exception(e)
def schedule():
@@ -163,8 +170,8 @@ def schedule():
log.debug("Scheduling cache_release_data job")
scheduler.add_interval_task(action=cache_release_data,
taskname='Cache release data',
- initialdelay=0,
- interval=3600)
+ initialdelay=300,
+ interval=60)
# If we're the masher, then handle the costly metric regenration
if not config.get('masher'):
diff --git a/bodhi/metrics.py b/bodhi/metrics.py
index 6802c8c..2ef631e 100644
--- a/bodhi/metrics.py
+++ b/bodhi/metrics.py
@@ -22,7 +22,7 @@ from turbogears import expose, config, flash, redirect
from turbogears.controllers import Controller
from bodhi.util import Singleton, get_age_in_days
-from bodhi.model import PackageUpdate, Release
+from bodhi.model import PackageUpdate, Release, hub
log = logging.getLogger(__name__)
@@ -107,7 +107,6 @@ class AllMetric(Metric):
self.months += m
def get_widget(self, data):
- log.debug("%s.get_widget(%s)" % (self.__class__.__name__, data))
return TurboFlot([
{
'data' : data['all'],
@@ -135,7 +134,7 @@ class AllMetric(Metric):
{
'xaxis' : {'ticks': data['months']},
},
- label = '%s Updates' % self.release
+ label = '%s Updates' % self.release.long_name
)
def get_data(self):
@@ -148,7 +147,7 @@ class MostUpdatedMetric(Metric):
A metric that calculates what packages have been updated the most.
"""
def __init__(self, release):
- self.release = release
+ self.release = release.long_name
self.data = {}
self.pkgs = []
@@ -183,7 +182,7 @@ class MostUpdatedMetric(Metric):
{
'xaxis': {'ticks': data['pkgs']}
},
- label = 'Most Updated Packages in %s' % self.release
+ label = 'Most Updated Packages in %s' % self.release.long_name
)
@@ -192,7 +191,7 @@ class ActiveDevsMetric(Metric):
A metric that calculates which developers have pushed out the most updates
"""
def __init__(self, release):
- self.release = release
+ self.release = release.long_name
self.users = {} # { user : # updates }
self.data = {}
@@ -224,7 +223,7 @@ class ActiveDevsMetric(Metric):
{
'xaxis': {'ticks': data['people']}
},
- label = 'Most updates per developer in %s' % self.release
+ label = 'Most updates per developer in %s' % self.release.long_name
)
@@ -235,7 +234,7 @@ class KarmaMetric(Metric):
"""
def __init__(self, release):
self.data = {} # { pkg : karma }
- self.release = release
+ self.release = release.long_name
self.bestpkgs = {}
self.bestdata = []
self.worstpkgs = {}
@@ -281,7 +280,7 @@ class TopTestersMetric(Metric):
testing feedback for updates
"""
def __init__(self, release):
- self.release = release
+ self.release = release.long_name
self.data = {} # { person : # of comments }
self.people = {}
@@ -317,7 +316,7 @@ class TopTestersMetric(Metric):
{
'xaxis': {'ticks': data['people']}
},
- label = 'Top %s testers' % self.release
+ label = 'Top %s testers' % self.release.long_name
)
@@ -326,7 +325,7 @@ class MostTestedMetric(Metric):
A metric that calculates the packages with the most +1/-1 comments
"""
def __init__(self, release):
- self.release = release
+ self.release = release.long_name
self.data = {} # {pkg: # of +1/-1's}
self.tested_data = []
self.tested_pkgs = {}
@@ -364,11 +363,48 @@ class MostTestedMetric(Metric):
)
+class UpdateTypeMetric(Metric):
+ """
+ This metric calculates the number of updates of various types for all
+ releases. This data is used by the sidebar in our master template. It is
+ generated by the masher, cached in the Release.metrics column, which is
+ then cached by our frontends every day.
+ """
+ def __init__(self, release):
+ self.release = {
+ 'id': release.id,
+ 'name': release.name,
+ 'long_name': release.long_name,
+ 'num_pending': 0,
+ 'num_testing': 0,
+ 'num_stable': 0,
+ 'num_obsolete': 0,
+ 'num_security': 0,
+ 'num_bugfix': 0,
+ 'num_enhancement': 0,
+ 'num_newpackage': 0,
+ }
+
+ def update(self, update):
+ self.release['num_%s' % update.status] += 1
+ if update.pushed:
+ self.release['num_%s' % update.type] += 1
+
+ def done(self):
+ pass
+
+ def get_data(self):
+ return self.release
+
+ def get_widget(self, data):
+ pass
+
+
##
## All of the metrics that we are going to generate
##
metrics = [AllMetric, MostUpdatedMetric, ActiveDevsMetric, KarmaMetric,
- TopTestersMetric, MostTestedMetric]
+ TopTestersMetric, MostTestedMetric, UpdateTypeMetric,]
class MetricData(Singleton):
@@ -379,7 +415,7 @@ class MetricData(Singleton):
def get_widgets(self, release):
""" Return the metrics for a specified release.
-
+
If our metric widgets are more than a day old, recreate them with
fresh metrics from our database.
"""
@@ -392,12 +428,13 @@ class MetricData(Singleton):
if not rel.metrics:
log.warning("No metrics found for %s" % rel.name)
return
- self.init_metrics(rel)
+ #self.init_metrics(rel) # Really?
if not freshwidgets.has_key(rel.name):
freshwidgets[rel.name] = {}
for metric in self.metrics:
- freshwidgets[rel.name][metric.__class__.__name__] = \
- metric.get_widget(rel.metrics[metric.__class__.__name__])
+ widget = metric.get_widget(rel.metrics[metric.__class__.__name__])
+ if widget:
+ freshwidgets[rel.name][metric.__class__.__name__] = widget
self.widgets = freshwidgets
self.age = datetime.utcnow()
@@ -407,27 +444,38 @@ class MetricData(Singleton):
""" Initialize our Metric objects for a given release
"""
self.metrics = []
for metric in metrics:
- self.metrics.append(metric(release.long_name))
+ self.metrics.append(metric(release))
def refresh(self):
""" Refresh all of the metrics for all releases.
-
+
For each release, initialize our metrics objects, and feed them every
update for that release. Do the necessary calculations, and then save
our metrics to the database in the Release.metrics PickleCol.
"""
log.info("Doing a hard refresh of our metrics data")
metrics = {}
- for release in Release.select():
+ updates = {} # {release: [updates,]}
+ all_updates = list(PackageUpdate.select())
+ releases = list(Release.select())
+ for release in releases:
+ updates[release.name] = []
+ for update in all_updates:
+ updates[update.release.name].append(update)
+ for release in releases:
+ log.debug("Calculating metrics for %s" % release.name)
self.init_metrics(release)
- for update in PackageUpdate.select(
- PackageUpdate.q.releaseID == release.id):
+ for update in updates[release.name]:
for metric in self.metrics:
metric.update(update)
for metric in self.metrics:
metric.done()
metrics[metric.__class__.__name__] = metric.get_data()
release.metrics = metrics
+ hub.commit()
+ del all_updates
+ del releases
+ log.info("Metrics generation complete!")
class MetricsController(Controller):
@@ -446,5 +494,6 @@ class MetricsController(Controller):
widgets = MetricData().get_widgets(release)
if not widgets:
return dict(metrics=[], title="Metrics currently unavailable")
- return dict(metrics=[widgets[name.__name__] for name in metrics],
+ return dict(metrics=[widgets[name.__name__] for name in metrics
+ if name.__name__ in widgets],
title="%s Update Metrics" % rel.long_name)
diff --git a/bodhi/model.py b/bodhi/model.py
index 8257ea3..9d3d057 100644
--- a/bodhi/model.py
+++ b/bodhi/model.py
@@ -873,20 +873,10 @@ class Releases(Singleton):
'name': release.name,
'id': release.id,
}
-
- # Count the number of different types of updates for this release
- for status in ('pending', 'testing', 'stable'):
- rel['num_%s' % status] = PackageUpdate.select(
- AND(PackageUpdate.q.releaseID == release.id,
- PackageUpdate.q.status == status)).count()
-
- # Count the number of pushed security updates for this release
- rel['num_security'] = PackageUpdate.select(
- AND(PackageUpdate.q.type == 'security',
- PackageUpdate.q.releaseID == release.id,
- PackageUpdate.q.pushed == True)).count()
-
+ if not release.metrics or 'UpdateTypeMetric' not in release.metrics:
+ log.warning("Release metrics have not been generated!")
+ return
+ rel.update(release.metrics['UpdateTypeMetric'])
releases.append(rel)
releases.sort(lambda x, y: cmp(x['name'], y['name']))
-
self.data = releases
commit deabe9f729538f8474eac7a530b0e1b85d11685e
Author: Luke Macken <lmacken(a)redhat.com>
Date: Tue Aug 12 12:02:03 2008 -0400
Change our default WSGI config to only use 1 process (default)
diff --git a/apache/bodhi.conf b/apache/bodhi.conf
index 0c126d3..a0be3b4 100644
--- a/apache/bodhi.conf
+++ b/apache/bodhi.conf
@@ -1,6 +1,6 @@
Alias /updates/static /usr/share/bodhi/static
-WSGIDaemonProcess bodhi user=apache processes=4 threads=2 maximum-requests=1000
display-name=bodhi
+WSGIDaemonProcess bodhi user=apache maximum-requests=1000 display-name=bodhi
WSGISocketPrefix run/wsgi
WSGIRestrictStdout On
WSGIRestrictSignal Off