~launchpad-pqm/launchpad/devel

4417.4.1 by Tom Haddon
First draft of script monitoring
1
#!/usr/bin/python2.4
2
# Copyright 2007 Canonical Ltd.  All rights reserved.
3
4
"""Monitor scripts."""
5
6
__metaclass__ = type
4417.4.9 by Tom Haddon
Checking command line options
7
__all__ = ['check_script']
4417.4.1 by Tom Haddon
First draft of script monitoring
8
9
import _pythonpath
10
4417.4.11 by Tom Haddon
Use MAX(date_completed) as cleaner that ORDER BY and LIMIT, clearer error messages and formatting
11
from datetime import datetime, timedelta
4417.4.14 by Tom Haddon
Using own email to send out notifications
12
from email.MIMEText import MIMEText
4417.4.1 by Tom Haddon
First draft of script monitoring
13
from optparse import OptionParser
14
from time import strftime
4417.4.14 by Tom Haddon
Using own email to send out notifications
15
import smtplib
4417.4.1 by Tom Haddon
First draft of script monitoring
16
import sys
17
18
from canonical.database.sqlbase import connect
19
from canonical.launchpad.scripts import db_options, logger_options, logger
4417.4.12 by Tom Haddon
Basic tests (not working) for script monitoring
20
from canonical.launchpad.scripts.scriptmonitor import check_script
21
4417.4.1 by Tom Haddon
First draft of script monitoring
22
23
def main():
4417.4.16 by Tom Haddon
Using sqlvalues, commenting on untested parts, and cleaning up
24
    # XXX: Tom Haddon 2007-07-12 
25
    # There's a lot of untested stuff here: parsing options and sending
26
    # emails - this should be moved into a testable location.
4417.4.22 by Tom Haddon
Clean up code after comments from Andrew Bennets
27
    # Also duplicated code in scripts/script-monitor-nagios.py
4417.4.1 by Tom Haddon
First draft of script monitoring
28
    parser = OptionParser(
4417.4.9 by Tom Haddon
Checking command line options
29
            '%prog [options] (minutes) (host:scriptname) [host:scriptname]'
4417.4.1 by Tom Haddon
First draft of script monitoring
30
            )
31
    db_options(parser)
32
    logger_options(parser)
33
34
    (options, args) = parser.parse_args()
35
4417.4.9 by Tom Haddon
Checking command line options
36
    if len(args) < 2:
37
        parser.error("Must specify at time in minutes and "
38
            "at least one host and script")
4417.4.1 by Tom Haddon
First draft of script monitoring
39
4417.4.6 by Tom Haddon
Cleaning up formatting
40
    # First argument is the number of minutes into the past
41
    # we want to look for the scripts on the specified hosts
4417.4.9 by Tom Haddon
Checking command line options
42
    try:
43
        minutes_ago, args = int(args[0]), args[1:]
44
        start_date = datetime.now() - timedelta(minutes=minutes_ago)
45
46
        completed_from = strftime("%Y-%m-%d %H:%M:%S", start_date.timetuple())
47
        completed_to = strftime("%Y-%m-%d %H:%M:%S", datetime.now().timetuple())
48
4417.4.16 by Tom Haddon
Using sqlvalues, commenting on untested parts, and cleaning up
49
        hosts_scripts = []
4417.4.9 by Tom Haddon
Checking command line options
50
        for arg in args:
4417.4.16 by Tom Haddon
Using sqlvalues, commenting on untested parts, and cleaning up
51
            try:
52
                hostname, scriptname = arg.split(':')
53
            except TypeError:
54
                parser.error(
55
                    "%r is not in the format 'host:scriptname'" % (arg,))
56
            hosts_scripts.append((hostname, scriptname))
57
    except ValueError:
4417.4.11 by Tom Haddon
Use MAX(date_completed) as cleaner that ORDER BY and LIMIT, clearer error messages and formatting
58
        parser.error("Must specify time in minutes and "
4417.4.9 by Tom Haddon
Checking command line options
59
            "at least one host and script")
4417.4.1 by Tom Haddon
First draft of script monitoring
60
61
    log = logger(options)
62
63
    try:
64
        log.debug("Connecting to database")
65
        con = connect(options.dbuser)
4417.4.16 by Tom Haddon
Using sqlvalues, commenting on untested parts, and cleaning up
66
        error_found = False
4417.4.14 by Tom Haddon
Using own email to send out notifications
67
        msg, subj = [], []
4417.4.16 by Tom Haddon
Using sqlvalues, commenting on untested parts, and cleaning up
68
        for hostname, scriptname in hosts_scripts:
69
            failure_msg = check_script(con, log, hostname, 
70
                scriptname, completed_from, completed_to)
71
            if failure_msg is not None:
4417.4.14 by Tom Haddon
Using own email to send out notifications
72
                msg.append(failure_msg)
4417.4.16 by Tom Haddon
Using sqlvalues, commenting on untested parts, and cleaning up
73
                subj.append("%s:%s" % (hostname, scriptname))
4417.4.11 by Tom Haddon
Use MAX(date_completed) as cleaner that ORDER BY and LIMIT, clearer error messages and formatting
74
                error_found = 2
4417.4.14 by Tom Haddon
Using own email to send out notifications
75
        if error_found:
76
            # Construct our email
77
            msg = MIMEText('\n'.join(msg))
78
            msg['Subject'] = "Scripts failed to run: %s" % ", ".join(subj)
5046.1.1 by Tom Haddon
Better from address for script monitor
79
            msg['From'] = 'script-failures@launchpad.net'
80
            msg['Reply-To'] = 'launchpad@lists.canonical.com'
4417.4.14 by Tom Haddon
Using own email to send out notifications
81
            msg['To'] = 'launchpad@lists.canonical.com'
82
            
83
            # Send out the email
84
            smtp = smtplib.SMTP()
85
            smtp.connect()
5046.1.1 by Tom Haddon
Better from address for script monitor
86
            smtp.sendmail('script-failures@launchpad.net', ['launchpad@lists.canonical.com'], msg.as_string())
4417.4.14 by Tom Haddon
Using own email to send out notifications
87
            smtp.close()
4417.4.16 by Tom Haddon
Using sqlvalues, commenting on untested parts, and cleaning up
88
            return 2
4417.4.1 by Tom Haddon
First draft of script monitoring
89
    except:
90
        log.exception("Unhandled exception")
91
        return 1
92
93
if __name__ == '__main__':
94
    sys.exit(main())