123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- #! /usr/bin/env python3
-
- import argparse
- import docker
- import sys
- import re
-
- def get_zones(container):
- out = container.exec_run(['pdnsutil', 'list-all-zones'])
- if out is not None:
- out = out.decode('UTF-8') # bytres to string
- zones = out.split('\n') # convert to list, one zone per line
- zones = list(filter(None, zones)) # remove any empty lines
- zones = zones[0:len(zones) - 1] # remove last line 'All zonecount: xx'
- return zones
- return None
-
- def add_zone(container, zone):
- out = container.exec_run(['pdnsutil', 'create-zone', zone])
- if out is not None:
- out = out.decode('UTF-8')
- if out != 'Creating empty zone \'%s\'\n' % (zone): # might to strict, but as we can not get return code
- return False
- out = container.exec_run(['pdnsutil', 'set-kind', zone, 'master'])
- out = out.decode('UTF-8')
- return out == '';
- return False
-
- def get_tsig_keys(container):
- out = container.exec_run(['pdnsutil', 'list-tsig-keys'])
- if out is not None:
- out = out.decode('UTF-8') # bytres to string
- keys = out.split('\n') # convert to list, one key per line
- keys = list(filter(None, keys)) # remove any empty lines
- keys = {"%s|%s" % (key[0], key[1]): key for key in [key.split(' ') for key in keys]}
- return keys
- return None
-
- def add_tsig_key(container, key_name, key_algo):
- out = container.exec_run(['pdnsutil', 'generate-tsig-key', key_name, key_algo])
- if out is not None:
- out = out.decode('UTF-8')
- match = re.search('Create new TSIG key %s %s (.+)' % (re.escape(key_name), re.escape(key_algo)), out)
- if match:
- key = match.group(1)
- return key
- else:
- return None
- return None
-
- def add_tsig_key_to_zone(container, zone, key_name):
- out = container.exec_run(['pdnsutil', 'set-meta', zone, 'TSIG-ALLOW-DNSUPDATE', key_name])
- if out is not None:
- out = out.decode('UTF-8')
- return out == 'Set \'%s\' meta TSIG-ALLOW-DNSUPDATE = %s\n' % (zone, key_name) # might to strict, but as we can not get return code
- return False
-
- def main():
- parser = argparse.ArgumentParser(description='Init Powerdns server')
- parser.add_argument('--dhcp-zone', dest='dhcp_zone', default=None, help='DHCP zone to create (eg: dhcp.city-a.example.com)')
- parser.add_argument('--site-zone', dest='site_zone', default=None, help='Site zone to create (eg: city-a.example.com)')
- parser.add_argument('--rev-zone', dest='rev_zone', default=None, help='Reverse zone to create (eg: 100.15.10), arpa suffix will be added automatically')
- parser.add_argument('--tsig-key-name', dest='tsig_key_name', default='dhcpupdate', help='TSIG key name to add (eg: dnsupdate)')
- parser.add_argument('--tsig-key-algo', dest='tsig_key_algo', default='hmac-md5', help='TSIG key algorithm to use (eg: hmac-md5)')
- parser.add_argument('--container-pdns', dest='container_pdns', default='pdns-pdns', help='Name of pdns auth docker container (eg: pdns-pdns)')
-
- args = parser.parse_args()
-
- if args.dhcp_zone is None and args.site_zone is None:
- print('At least one of dhcp-zone or site-zone is required')
- return 64
-
- if args.rev_zone is not None and not args.rev_zone.endswith('.in-addr.arpa'):
- args.rev_zone = args.rev_zone + '.in-addr.arpa'
-
- print('Getting docker client instance...')
- try:
- client = docker.DockerClient(version='auto')
- client.ping()
- except Exception as e:
- print('Failed to ping docker server: %s' % (e))
- return 1
-
- print('Getting docker container %s...' % (args.container_pdns))
- try:
- container = client.containers.get(args.container_pdns)
- except Exception as e:
- print('Can not find container %s' % (e))
- return 2
-
- if container.status != 'running':
- print('Container is not running: %s' % (container.status))
- return 3
-
- print('Checking existing zones...')
- zones = get_zones(container)
- if zones is None:
- print('Failes to get existing zones: Unknown error')
- return 4
-
- print('Checking existing TSIG keys...')
- keys = get_tsig_keys(container)
- if keys is None:
- print('Failes to get existing TSIG keys: Unknown error')
- return 5
-
- if '%s.|%s.' % (args.tsig_key_name, args.tsig_key_algo) in keys:
- print('Not adding TSIG key %s %s: already exists' % (args.tsig_key_name, args.tsig_key_algo))
- tsig_key_secret = keys['%s.|%s.' % (args.tsig_key_name, args.tsig_key_algo)][2]
- else:
- print('Adding TSIG key %s %s...' % (args.tsig_key_name, args.tsig_key_algo))
- tsig_key_secret = add_tsig_key(container, args.tsig_key_name, args.tsig_key_algo)
- if tsig_key_secret is None:
- print('Failed to add TSIG key: Unknown error')
- return 6
-
-
- for zone in [args.dhcp_zone, args.site_zone, args.rev_zone]:
- if zone is not None:
- if zone in zones:
- print('Not adding zone %s: already exists' % (zone))
- else:
- print('Adding zone...')
- if not add_zone(container, zone):
- print('Failed to add zone: Unknown error')
- return 7
- print('Adding TSIG %s to zone %s...' % (args.tsig_key_name, zone))
- if not add_tsig_key_to_zone(container, zone, args.tsig_key_name):
- print('Failed to add TSIG key to zone: Unknown error')
- return 8
-
- print('DHCP_TSIG_KEY_NAME=%s' % (args.tsig_key_name))
- print('DHCP_TSIG_KEY_ALGO=%s' % (args.tsig_key_algo))
- print('DHCP_TSIG_KEY_SECRET=%s' % (tsig_key_secret))
-
- return 0
-
- if __name__ == '__main__':
- sys.exit(main())
|