#!/usr/bin/env python
# *-* encoding: utf8 *-*

import dns.resolver
import dns.reversename
import logging
import threading
import re
import sys
import time
import urllib

from optparse import OptionParser

LOG_FILE = '/var/log/yandex/checkDnsHosts.log'
CGROUP = 'direct_perl'

def getLogLevel(level, interactive):
    logger = logging.getLogger('stream logs to console')
    logger.setLevel(level=getattr(logging, level))
    formatter = logging.Formatter('%(levelname)s %(asctime)s %(message)s')
    log_file = LOG_FILE
    if interactive:
        ch = logging.StreamHandler()
    else:
        ch = logging.FileHandler(log_file, mode='a')
    ch.setLevel(level=getattr(logging, level))
    ch.setFormatter(formatter)
    logger.addHandler(ch)
    return logger

def getConductor(group):
    group = group.strip()
    req = urllib.urlopen('http://c.yandex-team.ru/api/groups2hosts/{0}'.format(group))
    if req.code != 200:
        raise ValueError('http error conductor request for {3}: {0} {1}'.format(req.code, req.reason, group))
    value = req.read().split()
    if len(value) == 0:
        raise ValueError('empty conductor group {0}'.format(group))
    return value

def resolvconf():
    rgx = re.compile('nameserver\s(\S+)')
    with open('/etc/resolv.conf', 'r') as fd:
       text = fd.read()
    return rgx.findall(text)

def resolver(i, ns, dnsname, errors):
    try:
        rr = dns.resolver.Resolver()
        rr.nameservers=[ns]
        names = [ rdata.address for rdata in rr.query(dnsname, 'AAAA') ]
        for name in names:
            rname = dns.reversename.from_address(name)
            ptrs = [ i.to_text().strip('.') for i in rr.query(rname, "PTR") ]
        if dnsname in ptrs:
            logger.debug("ns: {0}, dnsname: {1}, answer: {2}".format(ns, dnsname, names, ptrs))
        else:
            raise ValueError('AAAA dont eq PTR: {0}'.format(ptrs))
    except Exception as err:
        logger.critical("ns: {0}, dnsname: {1}, answer: {2}".format(ns, dnsname, str(err)))
        raise
        errors.append(dnsname)

def main(level='DEBUG', mode='BASIC'):
    global logger
    interactive = True if mode.count('BASIC') else False
    logger = getLogLevel(level, interactive)
    dnsservers = resolvconf()
    cgroup = CGROUP
    errors = []
    if len(dnsservers) == 0:
        logger.error("empty nameservers in resolv.conf: {0}".format(dnsservers))
    logger.debug(dnsservers)
    t = list()
    try:
        hosts = getConductor(cgroup)
        [ t.append(threading.Thread(target=resolver, args=(i, dnsservers[0], host, errors))) 
                                                         for (i, host) in enumerate(hosts) ]
        [ i.start() for i in t ]
        [ i.join() for i in t ]
        if len(errors) != 0:
            raise ValueError('found broken DNS hosts for {1}. Run: {0}'.format(sys.argv[0], cgroup))
    except Exception as err:
        logger.critical(err)
        if mode.count('MONRUN'): print '2; {0}'.format(str(err))
    else:
        if mode.count('MONRUN'): print '0; not found broken DNS hosts for {0}'.format(cgroup)
    

if __name__ == '__main__':
    USAGE = "usage: %prog"
    VERSION = "1.0.0"

    parser = OptionParser(usage=USAGE, version=VERSION)
    parser.add_option( "-d", "--debug", 
                       action="store_true", dest="debug",
                       help="debug mode"
                     )
    parser.add_option( "-m", "--monrun",
                       action="store_true", dest="monrun",
                       help="monrun mode"
                     )

    (option, args) = parser.parse_args()
    level = 'DEBUG' if option.debug else 'CRITICAL'
    mode = 'MONRUN' if option.monrun else 'BASIC'
    main(level, mode)
