| #!/usr/bin/python | |
| """ | |
| usage: | |
| ./dhcp_failed_machines.py /var/log/dhcp.log | |
| You can also run it directly on the gzip'd logs. | |
| This script basically expects to run from the dhcp machine, as it looks at | |
| /etc/dhcp/dhcpd.conf to be able to do reverse DNS lookups. It also expects the | |
| dhcp log to be copied to some local file. | |
| If you're lucky, there might still be a copy of this script already on the dhcp | |
| server at /tmp/looky.py. | |
| """ | |
| import gzip | |
| import itertools | |
| import pprint | |
| import re | |
| import sys | |
| lookups = {} | |
| with open('/etc/dhcp/dhcpd.conf', 'r') as f: | |
| for line in f: | |
| if line.startswith('#'): | |
| continue | |
| if line.split() and line.split()[0] == 'host': | |
| hostconf = list(itertools.takewhile(lambda x: x.strip() != '}', f)) | |
| d = dict([h.strip().split()[-2:] for h in hostconf]) | |
| hostname = d['ddns-hostname'].replace('"', '').replace(';', '') | |
| lookups[d['fixed-address'].replace(';', '')] = hostname | |
| offers = {} | |
| offenders = set() | |
| restarts = [] | |
| rgx = re.compile( | |
| r'(?P<command>[A-Z]+) (?:from|on|for) (?P<host>\d+.\d+.\d+.\d+)') | |
| server_restart_str = 'Internet Systems Consortium' | |
| def open_file(f): | |
| if f.endswith('.gz'): | |
| return gzip.open(f, 'r') | |
| else: | |
| return open(f, 'r') | |
| with open_file(sys.argv[1]) as f: | |
| for line in f: | |
| if server_restart_str in line: | |
| restarts.append(line) | |
| continue | |
| m = rgx.search(line) | |
| if m: | |
| command = m.group('command') | |
| host = m.group('host') | |
| if command == 'DHCPOFFER': | |
| offers[host] = offers.get(host, 0) + 1 | |
| if offers[host] > 2: | |
| offenders.add(host) | |
| if command == 'DHCPREQUEST': | |
| offers[host] = 0 | |
| if restarts: | |
| print 'DHCP restarts:\n %s' % ''.join(restarts) | |
| def lookup(h): | |
| return lookups.get(h, h) | |
| hosts = sorted([lookup(h) for h in offenders]) | |
| if len(sys.argv) == 2: | |
| pprint.pprint(hosts) | |
| else: | |
| warning = int(sys.argv[2]) | |
| critical = int(sys.argv[3]) | |
| if len(offenders) > critical: | |
| print ('DHCP Critical, number of duts with DHCP failure is %d: %s' % | |
| (len(hosts), ', '.join(hosts))) | |
| sys.exit(2) | |
| elif len(offenders) > warning: | |
| print ('DHCP Warning, number of duts with DHCP failure is %d: %s' % | |
| (len(hosts), ', '.join(hosts))) | |
| sys.exit(1) | |
| else: | |
| print ('DHCP OK, number of duts with DHCP failure is %d: %s' % | |
| (len(hosts), ', '.join(hosts))) | |
| sys.exit(0) |