]> Frank Brehm's Git Trees - pixelpark/admin-tools.git/commitdiff
Starting with dns-deploy-zones
authorFrank Brehm <frank.brehm@pixelpark.com>
Thu, 3 Aug 2017 09:17:02 +0000 (11:17 +0200)
committerFrank Brehm <frank.brehm@pixelpark.com>
Thu, 3 Aug 2017 09:17:02 +0000 (11:17 +0200)
dns-deploy-zones [new file with mode: 0755]
pp_lib/config_named_app.py [new file with mode: 0644]

diff --git a/dns-deploy-zones b/dns-deploy-zones
new file mode 100755 (executable)
index 0000000..cd50b74
--- /dev/null
@@ -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 <frank.brehm@pixelpark.com>'
+__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 (file)
index 0000000..e5e2e35
--- /dev/null
@@ -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