Hotfix pkgdb-sync-bugzilla to automatically send notifications
This commit is contained in:
parent
3cba755812
commit
2198e5709c
1 changed files with 76 additions and 5 deletions
|
@ -32,9 +32,12 @@ __requires__ = ['SQLAlchemy >= 0.7', 'jinja2 >= 2.4']
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import datetime
|
||||||
|
import time
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import itertools
|
import itertools
|
||||||
|
import json
|
||||||
import xmlrpclib
|
import xmlrpclib
|
||||||
import codecs
|
import codecs
|
||||||
import smtplib
|
import smtplib
|
||||||
|
@ -70,18 +73,24 @@ NOTIFYEMAIL = pkgdb2.APP.config.get('PKGDB2_BUGZILLA_NOTIFY_EMAIL')
|
||||||
PKGDBSERVER = pkgdb2.APP.config.get('SITE_URL')
|
PKGDBSERVER = pkgdb2.APP.config.get('SITE_URL')
|
||||||
DRY_RUN = pkgdb2.APP.config.get('PKGDB2_BUGZILLA_DRY_RUN', False)
|
DRY_RUN = pkgdb2.APP.config.get('PKGDB2_BUGZILLA_DRY_RUN', False)
|
||||||
|
|
||||||
|
EMAIL_FROM = 'accounts@fedoraproject.org'
|
||||||
|
DATA_CACHE = '/var/tmp/pkgdb_sync_bz.json'
|
||||||
|
|
||||||
# When querying for current info, take segments of 1000 packages a time
|
# When querying for current info, take segments of 1000 packages a time
|
||||||
BZ_PKG_SEGMENT = 1000
|
BZ_PKG_SEGMENT = 1000
|
||||||
|
|
||||||
|
|
||||||
class DataChangedError(Exception):
|
class DataChangedError(Exception):
|
||||||
'''Raised when data we are manipulating changes while we're modifying it.'''
|
'''Raised when data we are manipulating changes while we're modifying it.'''
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def segment(iterable, chunk, fill=None):
|
def segment(iterable, chunk, fill=None):
|
||||||
'''Collect data into `chunk` sized block'''
|
'''Collect data into `chunk` sized block'''
|
||||||
args = [iter(iterable)] * chunk
|
args = [iter(iterable)] * chunk
|
||||||
return itertools.izip_longest(*args, fillvalue=fill)
|
return itertools.izip_longest(*args, fillvalue=fill)
|
||||||
|
|
||||||
|
|
||||||
class ProductCache(dict):
|
class ProductCache(dict):
|
||||||
def __init__(self, bz, acls):
|
def __init__(self, bz, acls):
|
||||||
self.bz = bz
|
self.bz = bz
|
||||||
|
@ -284,7 +293,7 @@ class Bugzilla(object):
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
def send_email(fromAddress, toAddress, subject, message):
|
def send_email(fromAddress, toAddress, subject, message, ccAddress=None):
|
||||||
'''Send an email if there's an error.
|
'''Send an email if there's an error.
|
||||||
|
|
||||||
This will be replaced by sending messages to a log later.
|
This will be replaced by sending messages to a log later.
|
||||||
|
@ -293,12 +302,70 @@ def send_email(fromAddress, toAddress, subject, message):
|
||||||
msg.add_header('To', ','.join(toAddress))
|
msg.add_header('To', ','.join(toAddress))
|
||||||
msg.add_header('From', fromAddress)
|
msg.add_header('From', fromAddress)
|
||||||
msg.add_header('Subject', subject)
|
msg.add_header('Subject', subject)
|
||||||
|
if ccAddress is not None:
|
||||||
|
msg.add_header('Cc', ','.join(ccAddress))
|
||||||
msg.set_payload(message)
|
msg.set_payload(message)
|
||||||
smtp = smtplib.SMTP('bastion')
|
smtp = smtplib.SMTP('bastion')
|
||||||
smtp.sendmail(fromAddress, toAddress, msg.as_string())
|
smtp.sendmail(fromAddress, toAddress, msg.as_string())
|
||||||
smtp.quit()
|
smtp.quit()
|
||||||
|
|
||||||
|
|
||||||
|
def notify_users(errors):
|
||||||
|
''' Browse the list of errors and when we can retrieve the email
|
||||||
|
address, use it to notify the user about the issue.
|
||||||
|
'''
|
||||||
|
tmpl_email = pkgdb2.APP.config.get('PKGDB_SYNC_BUGZILLA_EMAIL', None)
|
||||||
|
if not tmpl_email:
|
||||||
|
print 'No template email configured in the configuration file, '\
|
||||||
|
'no notification sent to the users'
|
||||||
|
return
|
||||||
|
|
||||||
|
data = {}
|
||||||
|
if os.path.exists(DATA_CACHE):
|
||||||
|
try:
|
||||||
|
with open(DATA_CACHE) as stream:
|
||||||
|
data = json.load(stream)
|
||||||
|
except Exception as err:
|
||||||
|
print 'Could not read the json file at %s: \nError: %s' % (
|
||||||
|
DATA_CACHE, err)
|
||||||
|
|
||||||
|
new_data = {}
|
||||||
|
for error in errors:
|
||||||
|
notify_user = False
|
||||||
|
if 'The name ' in error and ' is not a valid username' in error:
|
||||||
|
user_email = error.split(' is not a valid username')[0].split(
|
||||||
|
'The name ')[1].strip()
|
||||||
|
now = datetime.datetime.utcnow()
|
||||||
|
|
||||||
|
# See if we already know about this user
|
||||||
|
if user_email in data and data[user_email]['last_update']:
|
||||||
|
last_update = datetime.datetime.fromtimestamp(
|
||||||
|
int(data[user_email]['last_update']))
|
||||||
|
# Only notify users once per hour
|
||||||
|
if (now - last_update).seconds >= 3600:
|
||||||
|
notify_user = True
|
||||||
|
else:
|
||||||
|
new_data[user_email] = data[user_email]
|
||||||
|
elif not data or user_email not in data:
|
||||||
|
notify_user = True
|
||||||
|
|
||||||
|
if notify_user:
|
||||||
|
send_email(
|
||||||
|
EMAIL_FROM,
|
||||||
|
[user_email],
|
||||||
|
subject='Please fix your bugzilla.redhat.com account',
|
||||||
|
message=tmpl_email,
|
||||||
|
ccAddress=NOTIFYEMAIL,
|
||||||
|
)
|
||||||
|
|
||||||
|
new_data[user_email] = {
|
||||||
|
'last_update': time.mktime(now.timetuple())
|
||||||
|
}
|
||||||
|
|
||||||
|
with open(DATA_CACHE, 'w') as stream:
|
||||||
|
json.dump(new_data, stream)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
sys.stdout = codecs.getwriter('utf-8')(sys.stdout)
|
sys.stdout = codecs.getwriter('utf-8')(sys.stdout)
|
||||||
|
|
||||||
|
@ -328,7 +395,7 @@ if __name__ == '__main__':
|
||||||
for product in acls.keys():
|
for product in acls.keys():
|
||||||
if product not in ('Fedora', 'Fedora EPEL'):
|
if product not in ('Fedora', 'Fedora EPEL'):
|
||||||
continue
|
continue
|
||||||
for pkg in acls[product]:
|
for pkg in sorted(acls[product]):
|
||||||
if DRY_RUN:
|
if DRY_RUN:
|
||||||
print pkg
|
print pkg
|
||||||
pkgInfo = acls[product][pkg]
|
pkgInfo = acls[product][pkg]
|
||||||
|
@ -355,12 +422,16 @@ if __name__ == '__main__':
|
||||||
except xmlrpclib.Error, e:
|
except xmlrpclib.Error, e:
|
||||||
# An error occurred in the xmlrpc call. Shouldn't happen but
|
# An error occurred in the xmlrpc call. Shouldn't happen but
|
||||||
# we better see what it is
|
# we better see what it is
|
||||||
errors.append(str(e.args))
|
errors.append('%s -- %s' % (pkg, e.args[-1]))
|
||||||
|
|
||||||
# Send notification of errors
|
# Send notification of errors
|
||||||
if errors:
|
if errors:
|
||||||
#print '[DEBUG]', '\n'.join(errors)
|
if DRY_RUN:
|
||||||
send_email('accounts@fedoraproject.org',
|
print '[DEBUG]', '\n'.join(errors)
|
||||||
|
else:
|
||||||
|
notify_users(errors)
|
||||||
|
send_email(
|
||||||
|
EMAIL_FROM,
|
||||||
NOTIFYEMAIL,
|
NOTIFYEMAIL,
|
||||||
'Errors while syncing bugzilla with the PackageDB',
|
'Errors while syncing bugzilla with the PackageDB',
|
||||||
'''
|
'''
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue