changeset 99:7888fe374e11

Add support for notification mails in case of build errors This involves a new status field notification_mail to keep track of whether a notification has been sent for a particular build attempt and two programs to list the pending notifications and to send the pending notifications (similar to how the static web pages are published) as well as the corresponding configuration files.
author Bernhard Herzog <bh@intevation.de>
date Tue, 19 Feb 2008 19:19:23 +0000
parents f7b9c7113c46
children aea6b97e7c68
files bin/listpendingnotifications.py bin/sendnotificationmails.py demonotification.cfg notification-template.txt treepkg/packager.py treepkg/status.py
diffstat 6 files changed, 175 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/listpendingnotifications.py	Tue Feb 19 19:19:23 2008 +0000
@@ -0,0 +1,32 @@
+#! /usr/bin/python2.4
+# Copyright (C) 2008 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh@intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""List tracks and revisions where notifications are pending"""
+
+import treepkgcmd
+from treepkg.options import create_parser
+from treepkg.report import get_packager_group
+
+def parse_commandline():
+    return create_parser().parse_args()
+
+def list_notifications(config_file):
+    group = get_packager_group(config_file)
+    for track in group.get_package_tracks():
+        for revision in track.get_revisions():
+            if revision.status.notification_mail.name == "notification_pending":
+                print "%s %s %d" % (revision.status.status.name,
+                                    track.name, revision.revision)
+                revision.status.notification_sent()
+
+
+def main():
+    options, args = parse_commandline()
+    list_notifications(options.config_file)
+
+main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/sendnotificationmails.py	Tue Feb 19 19:19:23 2008 +0000
@@ -0,0 +1,75 @@
+#! /usr/bin/python2.4
+# Copyright (C) 2008 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh@intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""Send pending notification mails"""
+
+import os
+import smtplib
+import email
+import email.Utils
+from optparse import OptionParser
+from ConfigParser import SafeConfigParser
+
+import treepkgcmd
+from treepkg.readconfig import read_config_section
+from treepkg.run import capture_output
+from treepkg.cmdexpand import cmdexpand
+
+notification_desc = ["build_user", "build_host", "build_listpending",
+                     "notification_template", "base_url",
+                     "smtp_host", ("smtp_port", int),
+                     ]
+
+def read_config(filename):
+    parser = SafeConfigParser()
+    parser.read([filename])
+    return read_config_section(parser, "notification", notification_desc)
+
+def parse_commandline():
+    parser = OptionParser()
+    parser.set_defaults(config_file=os.path.join(treepkgcmd.topdir,
+                                                 "notification.cfg"))
+    parser.add_option("--config-file",
+                      help=("The configuration file."
+                            " Default notification.cfg"))
+    return parser.parse_args()
+
+
+def send_mail(config, raw_message):
+    msg = email.message_from_string(raw_message)
+    sender = email.Utils.parseaddr(msg["From"])[1]
+    recipients = [addr[1] for addr
+                  in email.Utils.getaddresses(msg.get_all("To", [])
+                                              + msg.get_all("Cc", []))]
+    server = smtplib.SMTP(config["smtp_host"], config["smtp_port"])
+    server.sendmail(sender, recipients, raw_message)
+    server.quit()
+
+
+def send_notification_mails(config_filename):
+    config = read_config(config_filename)
+
+    template = open(config["notification_template"]).read()
+
+    lines = capture_output(cmdexpand("ssh $build_user$@$build_host"
+                                     " $build_listpending",
+                                     **config))
+    for line in lines.splitlines():
+        words = line.split()
+        if len(words) == 3:
+            status, track, revision = words
+            values = config.copy()
+            values.update(locals())
+            send_mail(config, template % values)
+
+
+def main():
+    options, args = parse_commandline()
+    send_notification_mails(options.config_file)
+
+main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/demonotification.cfg	Tue Feb 19 19:19:23 2008 +0000
@@ -0,0 +1,38 @@
+# Demo config file for sendnotificationmails.py.  The default config
+# file used by sendnotificationmails.py is notification.cfg, so to use
+# this file as the basis for your configuration, copy or rename this
+# file and adapt it to your needs.
+
+[notification]
+
+# Username and host on which the treepackager runs.
+# sendnotificationmails.py has to be able to connect to that host as the
+# builduser via ssh without knowning the password.  This is best
+# achieved with the ssh-agent.
+build_user: builder
+build_host: localhost
+
+# the program to run on build_host to list the pending notifications
+# currently sendnotificationmails.py assumes that the default
+# configuration for that program works.
+build_listpending: ~/treepkg/bin/listpendingnotifications.py
+
+
+# Template of the notification email.  The expanded text is sent as the
+# entire email.  This means that the file should contain both the
+# headers and the body of the email.  The recipients of the mail are
+# taken from the expanded template's To: and CC: headers.  The smtp
+# envelope sender is taken from the From: header.
+#
+#  Substitutions have the form %(NAME)s where NAME can be one of these:
+#
+#  track       The name of the package track
+#
+#  revision    The revision number for which the notification has to be sent
+#
+#
+notification_template: notification_template.txt
+
+# host/port of the smtp server to use
+smtp_host: localhost
+smtp_port: 25
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/notification-template.txt	Tue Feb 19 19:19:23 2008 +0000
@@ -0,0 +1,16 @@
+From: TreePackager <treepkg@example.com>
+To: Project Developemen List <project-devel@example.com>
+Subject: TreePackager: error builder %(track)s rev. %(revision)s
+MIME-Version: 1.0
+Content-type: text/plain
+
+Hello,
+
+an error occurred while building the %(track)s packages for revision
+%(revision)s.  Details are available in the build log:
+
+  http://example.com/treepkg/%(track)s/%(revision)s/build_log.txt
+
+General information about the status of the packages is available at
+
+  http://example.com/treepkg/
--- a/treepkg/packager.py	Mon Nov 26 15:17:04 2007 +0000
+++ b/treepkg/packager.py	Tue Feb 19 19:19:23 2008 +0000
@@ -1,4 +1,4 @@
-# Copyright (C) 2007 by Intevation GmbH
+# Copyright (C) 2007, 2008 by Intevation GmbH
 # Authors:
 # Bernhard Herzog <bh@intevation.de>
 #
@@ -264,6 +264,12 @@
         except:
             self.status.error()
             self.status.stop = datetime.datetime.utcnow()
+            # set the notification status last to avoid race conditions.
+            # The pending notification is for now the only situation
+            # where another process might modify the status file (the
+            # listpendingnotifications program will set it to
+            # "notification_sent")
+            self.status.notification_pending()
             raise
 
     def remove_package_dir(self):
--- a/treepkg/status.py	Mon Nov 26 15:17:04 2007 +0000
+++ b/treepkg/status.py	Tue Feb 19 19:19:23 2008 +0000
@@ -1,4 +1,4 @@
-# Copyright (C) 2007 by Intevation GmbH
+# Copyright (C) 2007, 2008 by Intevation GmbH
 # Authors:
 # Bernhard Herzog <bh@intevation.de>
 #
@@ -187,3 +187,9 @@
 
     start = DateFieldDesc(default=None)
     stop = DateFieldDesc(default=None)
+
+    notification_mail = EnumFieldDesc()
+    notification_mail.add("notification_sent",
+                          "notification mail has been sent", default=True)
+    notification_mail.add("notification_pending",
+                          "notification mail still needs to be sent")
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)