Alex Miller | 6faf3f1 | 2013-11-11 10:50:54 -0800 | [diff] [blame] | 1 | #!/usr/bin/python |
| 2 | |
| 3 | """ |
| 4 | usage: |
| 5 | ./dhcp_failed_machines.py /var/log/dhcp.log |
| 6 | |
| 7 | You can also run it directly on the gzip'd logs. |
| 8 | |
| 9 | This script basically expects to run from the dhcp machine, as it looks at |
| 10 | /etc/dhcp/dhcpd.conf to be able to do reverse DNS lookups. It also expects the |
| 11 | dhcp log to be copied to some local file. |
| 12 | |
| 13 | If you're lucky, there might still be a copy of this script already on the dhcp |
| 14 | server at /tmp/looky.py. |
| 15 | """ |
| 16 | |
| 17 | import gzip |
| 18 | import itertools |
| 19 | import pprint |
| 20 | import re |
| 21 | import sys |
| 22 | |
| 23 | lookups = {} |
| 24 | |
| 25 | with open('/etc/dhcp/dhcpd.conf', 'r') as f: |
| 26 | for line in f: |
| 27 | if line.startswith('#'): |
| 28 | continue |
| 29 | if line.split() and line.split()[0] == 'host': |
| 30 | hostconf = list(itertools.takewhile(lambda x: x.strip() != '}', f)) |
| 31 | d = dict([h.strip().split()[-2:] for h in hostconf]) |
| 32 | hostname = d['ddns-hostname'].replace('"', '').replace(';', '') |
| 33 | lookups[d['fixed-address'].replace(';', '')] = hostname |
| 34 | |
| 35 | |
| 36 | offers = {} |
| 37 | offenders = set() |
Prashanth B | 3b102f1 | 2014-06-04 18:37:50 -0700 | [diff] [blame] | 38 | restarts = [] |
Alex Miller | 6faf3f1 | 2013-11-11 10:50:54 -0800 | [diff] [blame] | 39 | |
| 40 | rgx = re.compile( |
| 41 | r'(?P<command>[A-Z]+) (?:from|on|for) (?P<host>\d+.\d+.\d+.\d+)') |
Prashanth B | 3b102f1 | 2014-06-04 18:37:50 -0700 | [diff] [blame] | 42 | server_restart_str = 'Internet Systems Consortium' |
| 43 | |
Alex Miller | 6faf3f1 | 2013-11-11 10:50:54 -0800 | [diff] [blame] | 44 | |
| 45 | def open_file(f): |
| 46 | if f.endswith('.gz'): |
| 47 | return gzip.open(f, 'r') |
| 48 | else: |
| 49 | return open(f, 'r') |
| 50 | |
| 51 | with open_file(sys.argv[1]) as f: |
| 52 | for line in f: |
Prashanth B | 3b102f1 | 2014-06-04 18:37:50 -0700 | [diff] [blame] | 53 | if server_restart_str in line: |
| 54 | restarts.append(line) |
| 55 | continue |
Alex Miller | 6faf3f1 | 2013-11-11 10:50:54 -0800 | [diff] [blame] | 56 | m = rgx.search(line) |
| 57 | if m: |
| 58 | command = m.group('command') |
| 59 | host = m.group('host') |
| 60 | if command == 'DHCPOFFER': |
| 61 | offers[host] = offers.get(host, 0) + 1 |
| 62 | if offers[host] > 2: |
| 63 | offenders.add(host) |
| 64 | if command == 'DHCPREQUEST': |
| 65 | offers[host] = 0 |
| 66 | |
Prashanth B | 3b102f1 | 2014-06-04 18:37:50 -0700 | [diff] [blame] | 67 | if restarts: |
| 68 | print 'DHCP restarts:\n %s' % ''.join(restarts) |
| 69 | |
Alex Miller | 6faf3f1 | 2013-11-11 10:50:54 -0800 | [diff] [blame] | 70 | def lookup(h): |
| 71 | return lookups.get(h, h) |
| 72 | |
Dan Shi | 6a12b8a | 2014-01-16 12:37:17 -0800 | [diff] [blame] | 73 | hosts = sorted([lookup(h) for h in offenders]) |
| 74 | if len(sys.argv) == 2: |
| 75 | pprint.pprint(hosts) |
| 76 | else: |
| 77 | warning = int(sys.argv[2]) |
| 78 | critical = int(sys.argv[3]) |
| 79 | if len(offenders) > critical: |
| 80 | print ('DHCP Critical, number of duts with DHCP failure is %d: %s' % |
| 81 | (len(hosts), ', '.join(hosts))) |
| 82 | sys.exit(2) |
| 83 | elif len(offenders) > warning: |
| 84 | print ('DHCP Warning, number of duts with DHCP failure is %d: %s' % |
| 85 | (len(hosts), ', '.join(hosts))) |
| 86 | sys.exit(1) |
| 87 | else: |
| 88 | print ('DHCP OK, number of duts with DHCP failure is %d: %s' % |
| 89 | (len(hosts), ', '.join(hosts))) |
Prashanth B | 3b102f1 | 2014-06-04 18:37:50 -0700 | [diff] [blame] | 90 | sys.exit(0) |