Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

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

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

ralphbean opened this issue Jun 12, 2013 · 9 comments

Comments

@ralphbean
Copy link
Contributor

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

This depends on #145 being in place first.

@tyll
Copy link
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.

@ralphbean
Copy link
Contributor Author

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'])

@tyll
Copy link
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.

@ralphbean
Copy link
Contributor Author

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.

@pypingou
Copy link
Member

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

@ralphbean
Copy link
Contributor Author

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

@pypingou
Copy link
Member

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
Copy link
Contributor Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants