diff -r b58236f9ea7b -r bfdf1633b2a1 bin/check-dhcp-hosts --- a/bin/check-dhcp-hosts Fri May 10 00:05:25 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,201 +0,0 @@ -#!/usr/bin/env python - -""" - Go through a dhcp conf file looking for fixed-address stanzas, and make sure that they are valid. -""" - -__version__ = '0.0.1-dev' - -import optparse -import codecs -import logging - -import socket - -log = logging.getLogger('main') - -# command-line options, global state -options = None - -def parse_options (argv) : - """ - Parse command-line arguments. - """ - - prog = argv[0] - - parser = optparse.OptionParser( - prog = prog, - usage = '%prog: [options]', - version = __version__, - - # module docstring - description = __doc__, - ) - - # logging - general = optparse.OptionGroup(parser, "General Options") - - general.add_option('-q', '--quiet', dest='loglevel', action='store_const', const=logging.ERROR, help="Less output") - general.add_option('-v', '--verbose', dest='loglevel', action='store_const', const=logging.INFO, help="More output") - general.add_option('-D', '--debug', dest='loglevel', action='store_const', const=logging.DEBUG, help="Even more output") - - parser.add_option_group(general) - - # input/output - parser.add_option('-c', '--input-charset', metavar='CHARSET', default='utf-8', - help="Encoding used for input files") - - # - parser.add_option('--doctest', action='store_true', - help="Run module doctests") - - # defaults - parser.set_defaults( - loglevel = logging.WARN, - ) - - # parse - options, args = parser.parse_args(argv[1:]) - - # configure - logging.basicConfig( - format = prog + ': %(name)s: %(levelname)s %(funcName)s : %(message)s', - level = options.loglevel, - ) - - return options, args - -def parse_fixedaddrs (file) : - """ - Go through lines in given .conf file, looking for fixed-address stanzas. - """ - - filename = file.name - - for lineno, line in enumerate(file) : - # comments? - if '#' in line : - line, comment = line.split('#', 1) - - else : - comment = None - - # whitespace - line = line.strip() - - if not line : - # empty - continue - - # grep - if 'fixed-address' in line : - # great parsing :) - fixedaddr = line.replace('fixed-address', '').replace(';', '').strip() - - log.debug("%s:%d: %s: %s", filename, lineno, fixedaddr, line) - - yield lineno, fixedaddr - -def resolve_addr (addr, af=socket.AF_INET, socktype=socket.SOCK_STREAM) : - """ - Resolve given address for given AF_INET, returning a list of resolved addresses. - - Raises an Exception if failed. - - >>> resolve_addr('127.0.0.1') - ['127.0.0.1'] - """ - - if not addr : - raise Exception("Empty addr: %r", addr) - - # resolve - result = socket.getaddrinfo(addr, None, af, socktype) - - #log.debug("%s: %s", addr, result) - - # addresses - addrs = list(sorted(set(sockaddr[0] for family, socktype, proto, canonname, sockaddr in result))) - - return addrs - -def check_file_hosts (file) : - """ - Check all fixed-address parameters in given file. - """ - - filename = file.name - fail = 0 - - for lineno, addr in parse_fixedaddrs(file) : - # lookup - try : - resolved = resolve_addr(addr) - - except Exception as e: - log.warning("%s:%d: failed to resolve: %s: %s", filename, lineno, addr, e) - fail += 1 - - else : - log.debug("%s:%d: %s: %r", filename, lineno, addr, resolved) - - return fail - -def open_file (path, mode, charset) : - """ - Open unicode-enabled file from path, with - using stdio. - """ - - if path == '-' : - # use stdin/out based on mode - stream, func = { - 'r': (sys.stdin, codecs.getreader), - 'w': (sys.stdout, codecs.getwriter), - }[mode[0]] - - # wrap - return func(charset)(stream) - - else : - # open - return codecs.open(path, mode, charset) - -def main (argv) : - global options - - options, args = parse_options(argv) - - if options.doctest : - import doctest - fail, total = doctest.testmod() - return fail - - if args : - # open files - input_files = [open_file(path, 'r', options.input_charset) for path in args] - - else : - # default to stdout - input_files = [open_file('-', 'r', options.input_charset)] - - # process zone data - for file in input_files : - log.info("Reading zone: %s", file) - - fail = check_file_hosts(file) - - if fail : - log.warn("DHCP hosts check failed: %d", fail) - return 2 - - else : - log.info("DHCP hosts check OK") - - return 0 - -if __name__ == '__main__': - import sys - - sys.exit(main(sys.argv)) -