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() 38 restarts = [] 39 40 rgx = re.compile( 41 r'(?P<command>[A-Z]+) (?:from|on|for) (?P<host>\d+.\d+.\d+.\d+)') 42 server_restart_str = 'Internet Systems Consortium' 43 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: 53 if server_restart_str in line: 54 restarts.append(line) 55 continue 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 67 if restarts: 68 print 'DHCP restarts:\n %s' % ''.join(restarts) 69 70 def lookup(h): 71 return lookups.get(h, h) 72 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))) 90 sys.exit(0) 91