Home | History | Annotate | Download | only in contrib
      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