mirror of
				https://github.com/github/octodns.git
				synced 2024-05-11 05:55:00 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			107 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			107 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
#!/usr/bin/env python
 | 
						|
'''
 | 
						|
Octo-DNS Reporter
 | 
						|
'''
 | 
						|
 | 
						|
from __future__ import absolute_import, division, print_function, \
 | 
						|
    unicode_literals
 | 
						|
 | 
						|
from concurrent.futures import ThreadPoolExecutor
 | 
						|
from dns.exception import Timeout
 | 
						|
from dns.resolver import NXDOMAIN, NoAnswer, NoNameservers, Resolver, query
 | 
						|
from logging import getLogger
 | 
						|
from sys import stdout
 | 
						|
import re
 | 
						|
 | 
						|
from six import text_type
 | 
						|
 | 
						|
from octodns.cmds.args import ArgumentParser
 | 
						|
from octodns.manager import Manager
 | 
						|
from octodns.zone import Zone
 | 
						|
 | 
						|
 | 
						|
class AsyncResolver(Resolver):
 | 
						|
 | 
						|
    def __init__(self, num_workers, *args, **kwargs):
 | 
						|
        super(AsyncResolver, self).__init__(*args, **kwargs)
 | 
						|
        self.executor = ThreadPoolExecutor(max_workers=num_workers)
 | 
						|
 | 
						|
    def query(self, *args, **kwargs):
 | 
						|
        return self.executor.submit(super(AsyncResolver, self).query, *args,
 | 
						|
                                    **kwargs)
 | 
						|
 | 
						|
 | 
						|
def main():
 | 
						|
    parser = ArgumentParser(description=__doc__.split('\n')[1])
 | 
						|
 | 
						|
    parser.add_argument('--config-file', required=True,
 | 
						|
                        help='The Manager configuration file to use')
 | 
						|
    parser.add_argument('--zone', required=True, help='Zone to dump')
 | 
						|
    parser.add_argument('--source', required=True, default=[], action='append',
 | 
						|
                        help='Source(s) to pull data from')
 | 
						|
    parser.add_argument('--num-workers', default=4,
 | 
						|
                        help='Number of background workers')
 | 
						|
    parser.add_argument('--timeout', default=1,
 | 
						|
                        help='Number seconds to wait for an answer')
 | 
						|
    parser.add_argument('server', nargs='+', help='Servers to query')
 | 
						|
 | 
						|
    args = parser.parse_args()
 | 
						|
 | 
						|
    manager = Manager(args.config_file)
 | 
						|
 | 
						|
    log = getLogger('report')
 | 
						|
 | 
						|
    try:
 | 
						|
        sources = [manager.providers[source] for source in args.source]
 | 
						|
    except KeyError as e:
 | 
						|
        raise Exception('Unknown source: {}'.format(e.args[0]))
 | 
						|
 | 
						|
    zone = manager.get_zone(args.zone)
 | 
						|
    for source in sources:
 | 
						|
        source.populate(zone)
 | 
						|
 | 
						|
    print('name,type,ttl,{},consistent'.format(','.join(args.server)))
 | 
						|
    resolvers = []
 | 
						|
    ip_addr_re = re.compile(r'^[\d\.]+$')
 | 
						|
    for server in args.server:
 | 
						|
        resolver = AsyncResolver(configure=False,
 | 
						|
                                 num_workers=int(args.num_workers))
 | 
						|
        if not ip_addr_re.match(server):
 | 
						|
            server = text_type(query(server, 'A')[0])
 | 
						|
        log.info('server=%s', server)
 | 
						|
        resolver.nameservers = [server]
 | 
						|
        resolver.lifetime = int(args.timeout)
 | 
						|
        resolvers.append(resolver)
 | 
						|
 | 
						|
    queries = {}
 | 
						|
    for record in sorted(zone.records):
 | 
						|
        queries[record] = [r.query(record.fqdn, record._type)
 | 
						|
                           for r in resolvers]
 | 
						|
 | 
						|
    for record, futures in sorted(queries.items(), key=lambda d: d[0]):
 | 
						|
        stdout.write(record.fqdn)
 | 
						|
        stdout.write(',')
 | 
						|
        stdout.write(record._type)
 | 
						|
        stdout.write(',')
 | 
						|
        stdout.write(text_type(record.ttl))
 | 
						|
        compare = {}
 | 
						|
        for future in futures:
 | 
						|
            stdout.write(',')
 | 
						|
            try:
 | 
						|
                answers = [text_type(r) for r in future.result()]
 | 
						|
            except (NoAnswer, NoNameservers):
 | 
						|
                answers = ['*no answer*']
 | 
						|
            except NXDOMAIN:
 | 
						|
                answers = ['*does not exist*']
 | 
						|
            except Timeout:
 | 
						|
                answers = ['*timeout*']
 | 
						|
            stdout.write(' '.join(answers))
 | 
						|
            # sorting to ignore order
 | 
						|
            answers = '*:*'.join(sorted(answers)).lower()
 | 
						|
            compare[answers] = True
 | 
						|
        stdout.write(',True\n' if len(compare) == 1 else ',False\n')
 | 
						|
 | 
						|
 | 
						|
if __name__ == '__main__':
 | 
						|
    main()
 |