From 1754b53f0749af8e34d24fd1b63039e46f4a39bb Mon Sep 17 00:00:00 2001 From: Frank Brehm Date: Thu, 3 Aug 2017 11:17:02 +0200 Subject: [PATCH] Starting with dns-deploy-zones --- dns-deploy-zones | 39 +++++++ pp_lib/config_named_app.py | 228 +++++++++++++++++++++++++++++++++++++ 2 files changed, 267 insertions(+) create mode 100755 dns-deploy-zones create mode 100644 pp_lib/config_named_app.py diff --git a/dns-deploy-zones b/dns-deploy-zones new file mode 100755 index 0000000..cd50b74 --- /dev/null +++ b/dns-deploy-zones @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 + +# Standard modules +import sys +import os +import logging +import locale + +# own modules: +cur_dir = os.getcwd() +base_dir = cur_dir + +if sys.argv[0] != '' and sys.argv[0] != '-c': + cur_dir = os.path.dirname(sys.argv[0]) +if os.path.exists(os.path.join(cur_dir, 'pp_lib')): + sys.path.insert(0, os.path.abspath(cur_dir)) + +from pp_lib.config_named_app import PpConfigNamedApp + +log = logging.getLogger(__name__) + +__author__ = 'Frank Brehm ' +__copyright__ = '(C) 2017 by Frank Brehm, Pixelpark GmbH, Berlin' + +appname = os.path.basename(sys.argv[0]) + +locale.setlocale(locale.LC_ALL, '') + +app = PpConfigNamedApp(appname=appname) +app.initialized = True + +if app.verbose > 2: + print("{c}-Object:\n{a}".format(c=app.__class__.__name__, a=app)) + +app() + +sys.exit(0) + +# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/pp_lib/config_named_app.py b/pp_lib/config_named_app.py new file mode 100644 index 0000000..e5e2e35 --- /dev/null +++ b/pp_lib/config_named_app.py @@ -0,0 +1,228 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +@author: Frank Brehm +@contact: frank.brehm@pixelpark.com +@copyright: © 2017 by Frank Brehm, Berlin +@summary: A module for the application class for configuring named +""" +from __future__ import absolute_import + +# Standard modules +import os +import logging +import logging.config +import re +import pwd +import glob +import copy +import textwrap +import socket + +# Third party modules +import six + +# Own modules +from .common import pp, to_bool + +from .cfg_app import PpCfgAppError, PpConfigApplication + +__version__ = '0.1.0' +LOG = logging.getLogger(__name__) + + +# ============================================================================= +class PpConfigNamedError(PpCfgAppError): + pass + + +# ============================================================================= +class PpConfigNamedApp(PpConfigApplication): + """ + Class for a application 'config-named' for configuring the BIND named daemon. + """ + + default_pdns_api_host = 'systemshare.pixelpark.com' + default_pdns_api_port = 8081 + default_pdns_api_root_path = '/api/v1/servers/localhost' + + default_zone_masters = [ + '217.66.53.86', + ] + + re_split_addresses = re.compile(r'[,;\s]+') + + # ------------------------------------------------------------------------- + def __init__(self, appname=None, version=__version__): + + self.pdns_api_host = self.default_pdns_api_host + self.pdns_api_port = self.default_pdns_api_port + self.pdns_api_root_path = self.default_pdns_api_root_path + self.pdns_api_key = None + + self.is_internal = False + self.zone_masters = copy.copy(self.default_zone_masters) + self.query_log = False + + description = textwrap.dedent('''\ + Generation of configuration of named (the BIND 9 name daemon). + ''').strip() + + super(PpConfigNamedApp, self).__init__( + appname=appname, version=version, description=description, + cfg_stems='dns-deploy-zones', + ) + + # ------------------------------------------------------------------------- + def init_arg_parser(self): + + is_internal_group = self.arg_parser.add_mutually_exclusive_group() + + is_internal_group.add_argument( + '--internal', '--not-public', dest='internal', action='store_true', + help="Creating a named configuration for a internal name server.", + ) + + is_internal_group.add_argument( + '--public', '--not-internal', dest='public', action='store_true', + help="Creating a named configuration for a public name server.", + ) + + query_log_group = self.arg_parser.add_mutually_exclusive_group() + + query_log_group.add_argument( + '--querylog', dest='querylog', action='store_true', + help="Enabling query logging in the named configuration.", + ) + + query_log_group.add_argument( + '--no-querylog', dest='no_querylog', action='store_true', + help="Disabling query logging in the named configuration.", + ) + + # ------------------------------------------------------------------------- + def perform_config(self): + + super(PpConfigNamedApp, self).perform_config() + + for section_name in self.cfg.keys(): + + if self.verbose > 3: + LOG.debug("Checking config section {!r} ...".format(section_name)) + + section = self.cfg[section_name] + + if section_name.lower() in ( + 'powerdns-api', 'powerdns_api', 'powerdnsapi', + 'pdns-api', 'pdns_api', 'pdnsapi' ): + self.set_api_options(section, section_name) + + if section_name.lower() == 'named': + self.set_named_options(section, section_name) + + self._perform_cmdline_opts() + + # ------------------------------------------------------------------------- + def _perform_cmdline_opts(self): + + if hasattr(self.args, 'internal') and self.args.internal: + self.is_internal = True + elif hasattr(self.args, 'public') and self.args.public: + self.is_internal = False + + if hasattr(self.args, 'querylog') and self.args.querylog: + self.query_log = True + elif hasattr(self.args, 'no_querylog') and self.args.no_querylog: + self.query_log = False + + # ------------------------------------------------------------------------- + def set_api_options(self, section, section_name): + + if self.verbose > 2: + LOG.debug("Evaluating config section {n!r}:\n{s}".format( + n=section_name, s=pp(section))) + + if 'host' in section: + v = section['host'] + host = v.lower().strip() + if host: + self.pdns_api_host = host + + if 'port' in section: + try: + port = int(section['port']) + if port <= 0 or port > 2**16: + raise ValueError( + "a port must be greater than 0 and less than {}.".format(2**16)) + except (TypeError, ValueError) as e: + LOG.error("Wrong port number {!r} in configuration section {!r}: {}".format( + section['port'], section_name, e)) + else: + self.pdns_api_port = port + + if 'root_path' in section: + path = section['root_path'] + if not os.path.isabs(path): + msg = ( + "The root path of the PowerDNS must be an absolute pathname " + "(found [{}]/root_path => {!r} in configuration.").format(section_name, path) + LOG.error(msg) + else: + self.pdns_api_root_path = path + + if 'key' in section: + key = section['key'].strip() + self.pdns_api_key = key + + # ------------------------------------------------------------------------- + def set_named_options(self, section, section_name): + + if self.verbose > 2: + LOG.debug("Evaluating config section {n!r}:\n{s}".format( + n=section_name, s=pp(section))) + + if 'is_internal' in section: + if section['is_internal'] is None: + self.is_internal = False + else: + self.is_internal = to_bool(section['is_internal']) + + if 'query_log' in section: + self.query_log = to_bool(section['query_log']) + + if 'masters' in section: + masters = [] + for m in self.re_split_addresses.split(section['masters']): + if m: + m = m.strip().lower() + try: + addr_info = socket.getaddrinfo( + m, 53, proto=socket.IPPROTO_TCP, family=socket.AF_INET) + except socket.gaierror as e: + msg = ( + "Invalid hostname or address {!r} found in " + "[{}]/masters: {}").format(m, section_name, e) + LOG.error(msg) + m = None + if m: + masters.append(m) + if masters: + self.zone_masters = masters + + # ------------------------------------------------------------------------- + def _run(self): + + if os.geteuid(): + LOG.error("You must be root to execute this script.") + self.exit(1) + LOG.info("Jetzt geht's looos") + +# ============================================================================= + +if __name__ == "__main__": + + pass + +# ============================================================================= + +# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 list -- 2.39.5