diff --git a/factory-package-news/announcer.py b/factory-package-news/announcer.py index d51ab5165..4fec2c651 100755 --- a/factory-package-news/announcer.py +++ b/factory-package-news/announcer.py @@ -1,16 +1,21 @@ #!/usr/bin/python +from __future__ import print_function + import httplib import re from urlparse import urlparse, urljoin import smtplib from email.mime.text import MIMEText import os +import osc import sys import email.utils import argparse import logging import yaml +import json +import pika from xdg.BaseDirectory import save_data_path from collections import namedtuple @@ -21,12 +26,12 @@ 'sender': 'noreply@opensuse.org', 'to': 'opensuse-factory@opensuse.org', 'relay': 'relay.suse.de', - 'url' : "http://download.opensuse.org/tumbleweed/iso/", - 'iso' : "openSUSE-Tumbleweed-DVD-x86_64-Current.iso", - 'name' : 'factory-announcer', - 'subject' : 'New Tumbleweed snapshot {version} released!', - 'changesfile' : "Changes.{version}.txt", - 'bodytemplate' : """ + 'url': "http://download.opensuse.org/tumbleweed/iso/", + 'iso': "openSUSE-Tumbleweed-DVD-x86_64-Current.iso", + 'name': 'factory-announcer', + 'subject': 'New Tumbleweed snapshot {version} released!', + 'changesfile': "Changes.{version}.txt", + 'bodytemplate': """ Please note that this mail was generated by a script. The described changes are computed based on the x86_64 DVD. The full online repo contains too many changes to be listed here. @@ -43,21 +48,85 @@ } -def _load_config(handle = None): + +def send_amqp_message(version, config): + """ Sends a rabbitmq message notifying about a new iso release + + This function sends a message over the openSUSE rabbitmq message bus + notifying about a new ISO being released. The message topic is:: + + opensuse.release.iso.publish + + The message's body contains the name of the release iso, the link to the + base url and the name of the changesfile. + + Args: + version (str): version string of the iso + config (namedtuple): configuration for this opensuse release, must + contain the following keys: iso, url, changesfile + + Returns: + Nothing + """ + amqp_url = osc.conf.config.get('ttm_amqp_url') + if amqp_url is None: + logger.error("No ttm_amqp_url configured in oscrc - No message will be" + " sent") + return + + topic = 'opensuse.release.iso.publish' + payload = {key: config[key] for key in config + if key in ("iso", "url", "changesfile")} + payload["version"] = version + body = json.dumps(payload) + + # copy-pasta from totest-manager.py: + # send amqp event + tries = 7 # arbitrary + for t in range(tries): + try: + notify_connection = pika.BlockingConnection( + pika.URLParameters(amqp_url)) + notify_channel = notify_connection.channel() + notify_channel.exchange_declare(exchange='pubsub', + exchange_type='topic', + passive=True, durable=True) + notify_channel.basic_publish(exchange='pubsub', + routing_key=topic, body=body) + notify_connection.close() + break + except pika.exceptions.ConnectionClosed as e: + logger.warn("Sending AMQP event did not work: {!s}. Retrying try " + "{!s} out of {!s}".format(e, t, tries)) + else: + logger.error("Could not send out AMQP event for {!s} tries, aborting." + .format(tries)) + + +def _load_config(handle=None): d = config_defaults y = yaml.safe_load(handle) if handle is not None else {} - return namedtuple('Config', sorted(d.keys()))(*[ y.get(p, d[p]) for p in sorted(d.keys()) ]) + return namedtuple('Config', sorted(d.keys()))(*[y.get(p, d[p]) for p in sorted(d.keys())]) + parser = argparse.ArgumentParser(description="Announce new snapshots") parser.add_argument("--dry", action="store_true", help="dry run") parser.add_argument("--debug", action="store_true", help="debug output") parser.add_argument("--verbose", action="store_true", help="verbose") -parser.add_argument("--from", dest='sender', metavar="EMAIL", help="sender email address") +parser.add_argument("--from", dest='sender', metavar="EMAIL", + help="sender email address") parser.add_argument("--to", metavar="EMAIL", help="recepient email address") -parser.add_argument("--relay", metavar="RELAY", help="SMTP relay server address") -parser.add_argument("--version", metavar="VERSION", help="announce specific version") -parser.add_argument("--config", metavar="FILE", type=argparse.FileType(), help="YAML config file to override defaults") -parser.add_argument("--dump-config", action="store_true", help="dump built in YAML config") +parser.add_argument("--relay", metavar="RELAY", + help="SMTP relay server address") +parser.add_argument("--version", metavar="VERSION", + help="announce specific version") +parser.add_argument("--config", metavar="FILE", + type=argparse.FileType(), + help="YAML config file to override defaults") +parser.add_argument("--dump-config", action="store_true", + help="dump built in YAML config") +parser.add_argument("--no-amqp-msg", action="store_true", + help="don't send a rabbitmq message") options = parser.parse_args() @@ -67,7 +136,7 @@ def _load_config(handle = None): format='%(asctime)s - %(module)s:%(lineno)d - %(levelname)s - %(message)s') if options.dump_config: - print yaml.dump(config_defaults, default_flow_style=False) + print(yaml.dump(config_defaults, default_flow_style=False)) sys.exit(0) config = _load_config(options.config) @@ -101,7 +170,7 @@ def _load_config(handle = None): m = re.search(r'(?:Snapshot|Build)([\d.]+)-Media', loc) if m is None: - raise Exception("failed to parse %s"%loc) + raise Exception("failed to parse %s" % loc) version = m.group(1) logger.debug("found version %s", version) @@ -145,8 +214,8 @@ def _load_config(handle = None): msg['Message-ID'] = email.utils.make_msgid() if options.dry: - print "sending ..." - print msg.as_string() + print("sending ...") + print(msg.as_string()) else: logger.info("announcing version {}".format(version)) s = smtplib.SMTP(options.relay) @@ -157,3 +226,5 @@ def _load_config(handle = None): os.symlink(version, tmpfn) os.rename(tmpfn, current_fn) + if not options.no_amqp_msg: + send_amqp_message(version, config)