Write a script to send emails before koji cert expirations #146

Closed
ralphbean opened this Issue Jun 12, 2013 · 9 comments

Comments

Projects
None yet
3 participants
Contributor

ralphbean commented Jun 12, 2013

This can query datanommer for "who got a new cert 6months - 1 week ago".

This depends on #145 being in place first.

Contributor

tyll commented Sep 24, 2013

you need to validate that only the last request is used per user, otherwise there would be unnecessary noise if a user requests two certs within 6 months.

Contributor

ralphbean commented Apr 9, 2014

How about something like this that we can keep in puppet/ansible and run as a weekly cronjob.

""" Send emails to Fedora users whose koji certs are about to expire.

We first get a list of Fedora users in the cla_done group.  Then we query
datagrepper for the history of when each user last changed their cert.  If that
event occurred inside a window (between 5.75 months ago and 6 months ago), then
send them an email letting them know their cert is about to expire.

Requires:   python-arrow python-fedora python-requests fedmsg
License:    LGPLv2+
Authors:    Ralph Bean <rbean@redhat.com>
"""

import arrow
import datetime
import email
import fedmsg
import fedora.client.fas2
import getpass
import smtplib
import requests

# This is a flag used to turn of email to the actual users
DEVELOPMENT = True

datagrepper_url = 'https://apps.fedoraproject.org/datagrepper/raw'

mail_server = 'bastion.fedoraproject.org'
message_template = """{human_name}/{username}:

This is an automated email sent to inform you that your Fedora Project Koji
certificate is about to expire.  Koji certificates are valid for 6 months and
our records indicate that you last recreated yours about {change_human}
on {change_date}.

Please run the following command to regenerate your certificate:

    $ /usr/bin/fedora-cert -n

For more information, see the following wiki page:
https://fedoraproject.org/wiki/Using_the_Koji_build_system#Fedora_Certificates
"""

# We want to alert users if their cert is going to expire this week.
now = arrow.utcnow()
six_months = 1.57785e7
one_week = 604800

window_delta = one_week
window_max = six_months
window_min = window_max - window_delta


def cert_changes(user):
    """ Generator that returns all the koji cert changes for a user.

    >>> user = 'ralph'
    >>> for change in cert_changes(user):
    ...     print change.humanize(), "on", change.format('YYYY-MM-DD')
    21 hours ago on 2014-04-08
    2 months ago on 2014-02-09
    8 months ago on 2013-08-12

    """

    def get_page(page):
        params = dict(
            rows_per_page=100,
            topic='org.fedoraproject.prod.fas.user.update',
            user=user,
            page=page,
        )
        return requests.get(datagrepper_url, params=params).json()

    data = get_page(1)
    pages = data['pages']

    for page in range(1, pages + 1):
        data = get_page(page)
        for message in data['raw_messages']:
            if 'certificate' in message['msg']['fields']:
                yield arrow.get(message['timestamp'])


def test_cert_changes():
    """ Just messing around... """
    for user in ['kevin', 'ralph', 'lmacken', 'pingou']:
        for change in cert_changes(user):
            print user, change.humanize(), "on", change.format('YYYY-MM-DD')


def fedora_users(credentials):
    return fedora.client.fas2.AccountSystem(
        username=credentials['username'],
        password=credentials['password'],
    ).people_by_groupname('cla_done')


def total_seconds(td):
    """ Take a datetime.timedelta object and return the total seconds.

    td.total_seconds() exists in the python 2.7 stdlib, but not in python 2.6.
    """
    return td.days * 24 * 60 * 60 + td.seconds + td.microseconds / 1000000.0


def to_address(user):
    if DEVELOPMENT:
        return 'ralph@fedoraproject.org'
    else:
        return user['email']


def send_email(user, last_change):
    print "send an email to %r since they last changed on %r" % (
        user, last_change.format('YYYY-MM-DD'))

    message = email.Message.Message()
    message.add_header('To', to_address(user))
    message.add_header('From', 'admin@fedoraproject.org')
    subject = 'Your Koji certificate expires within a week'
    message.add_header('Subject', subject)

    content = message_template.format(
        change_human=last_change.humanize(),
        change_date=last_change.format('YYYY-MM-DD'),
        **user
    )
    message.set_payload(content)

    server = smtplib.SMTP(mail_server)
    server.sendmail(
        fromaddress.encode('utf-8'),
        [to_address(user).encode('utf-8')],
        message.as_string().encode('utf-8'),
    )
    server.quit()


def main(credentials):
    print "* Querying FAS for a list of users"
    users = fedora_users(credentials)
    print "* Found %r people" % len(users)
    for user in users:
        #print "* Querying datagrepper for %r." % user['username'],
        changes = cert_changes(user['username'])

        try:
            latest = changes.next()
        except StopIteration:
            # Then the user has no changes in the fedmsg history.
            #print "No record of %r changing a cert." % user['username']
            continue

        print user['username'], "changed", latest.humanize(),
        print "on", latest.format('YYYY-MM-DD')

        delta = total_seconds(now - latest)
        if delta >= window_min and delta <= window_max:
            send_email(user, latest)


if __name__ == '__main__':
    # Load credentials from /etc/fedmsg.d/
    config = fedmsg.config.load_config()

    if 'fas_credentials' not in config:
        print "No 'fas_credentials' found in `fedmsg-config`..."
        username = raw_input("Enter your fas username: ")
        password = getpass.getpass("Enter your fas password: ")
        config['fas_credentials'] = dict(username=username, password=password)

    main(config['fas_credentials'])
Contributor

tyll commented Apr 9, 2014

There seems to be an
import arrow
missing.
I would change the Subject to be "Your Koji certificate expires within a week". Also I am not sure whether just encoding to utf-8 is correct for the sending the mail. Other than that it looks good at first sight.

Contributor

ralphbean commented Apr 9, 2014

Thanks! I fixed the import arrow and the subject.

I'm pretty sure the utf-8 encoding works. I took the code from some code I was working on this winter over here.

Owner

pypingou commented Apr 10, 2014

/usr/bin/fedora-packager-setup vs fedora-cert -n?

Contributor

ralphbean commented Apr 10, 2014

Is fedora-cert -n documented on the wiki? If so, where?

Owner

pypingou commented Apr 10, 2014

Good point, it doesn't seem to be very well documented, the only place I found it is at: http://fedoraproject.org/wiki/Package_update_HOWTO#Build_a_package_for_Rawhide

ralphbean closed this Apr 28, 2014

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment