]> Frank Brehm's Git Trees - pixelpark/admin-tools.git/commitdiff
Generated temp slave zones config file
authorFrank Brehm <frank.brehm@pixelpark.com>
Thu, 9 Nov 2017 18:03:38 +0000 (19:03 +0100)
committerFrank Brehm <frank.brehm@pixelpark.com>
Thu, 9 Nov 2017 18:03:38 +0000 (19:03 +0100)
pp_lib/deploy_zones_from_pdns.py
pp_lib/pdns_app.py

index e8c68c677687c10b76a02d0fba32fd6b82c0d006..3feeb5131c17c2f180cd1619bdeb22bbde539ba4 100644 (file)
@@ -17,6 +17,9 @@ import shlex, subprocess
 import copy
 import datetime
 import socket
+import tempfile
+import time
+import shutil
 
 from subprocess import Popen, TimeoutExpired, PIPE
 
@@ -40,7 +43,7 @@ from .pdns_record import compare_rrsets
 
 from .pidfile import PidFileError, InvalidPidFileError, PidFileInUseError, PidFile
 
-__version__ = '0.2.4'
+__version__ = '0.3.1'
 LOG = logging.getLogger(__name__)
 
 
@@ -60,6 +63,8 @@ class PpDeployZonesApp(PpPDNSApplication):
 
     default_named_conf_dir = '/etc'
     default_named_zones_cfg_file = 'named.zones.conf'
+    default_named_basedir = '/var/named'
+    default_named_slavedir = 'slaves'
 
     zone_masters_local = [
         '217.66.53.87',
@@ -105,6 +110,8 @@ class PpDeployZonesApp(PpPDNSApplication):
         # Configuration files and directories
         self.named_conf_dir = self.default_named_conf_dir
         self._named_zones_cfg_file = self.default_named_zones_cfg_file
+        self.named_basedir =  self.default_named_basedir
+        self._named_slavedir =  self.default_named_slavedir
 
         self.zone_masters = copy.copy(self.zone_masters_public)
         self.masters_configured = False
@@ -146,6 +153,18 @@ class PpDeployZonesApp(PpPDNSApplication):
         """The file for configuration of all own zones."""
         return os.path.join(self.named_conf_dir, self._named_zones_cfg_file)
 
+    # -------------------------------------------
+    @property
+    def named_slavedir_rel(self):
+        """The directory for zone files of slave zones."""
+        return self._named_slavedir
+
+    # -------------------------------------------
+    @property
+    def named_slavedir_abs(self):
+        """The directory for zone files of slave zones."""
+        return os.path.join(self.named_basedir, self._named_slavedir)
+
     # -------------------------------------------------------------------------
     def init_arg_parser(self):
 
@@ -206,6 +225,8 @@ class PpDeployZonesApp(PpPDNSApplication):
             section, section_name, 'config_dir', 'named_conf_dir', True)
         self._check_path_config(
             section, section_name, 'zones_cfg_file', '_named_zones_cfg_file', False)
+        self._check_path_config(section, section_name, 'base_dir', 'named_basedir', True)
+        self._check_path_config(section, section_name, 'slave_dir', '_named_slavedir', False)
 
         if 'masters' in section:
             self._get_masters_from_cfg(section['masters'], section_name)
@@ -306,6 +327,9 @@ class PpDeployZonesApp(PpPDNSApplication):
             self.zones = self.get_api_zones()
             self.zones.sort(key=lambda x: cmp_to_key(compare_fqdn)(x.name_unicode))
 
+            self.init_temp_objects()
+            self.generate_slave_cfg_file()
+
         finally:
             self.cleanup()
             self.pidfile = None
@@ -339,6 +363,127 @@ class PpDeployZonesApp(PpPDNSApplication):
                 shutil.rmtree(self.tempdir, False, emit_rm_err)
                 self.tempdir = None
 
+    # -------------------------------------------------------------------------
+    def init_temp_objects(self):
+        """Init temporary objects and properties."""
+
+        self.tempdir = tempfile.mkdtemp(
+            prefix=(self.appname + '.'), suffix='.tmp.d'
+        )
+        LOG.debug("Temporary directory: {!r}.".format(self.tempdir))
+
+        self.temp_zones_cfg_file = os.path.join(
+            self.tempdir, self.default_named_zones_cfg_file)
+
+        if self.verbose > 1:
+            LOG.debug("Temporary zones conf: {!r}".format(self.temp_zones_cfg_file))
+
+    # -------------------------------------------------------------------------
+    def generate_slave_cfg_file(self):
+
+        LOG.info("Generating {} ...".format(self.default_named_zones_cfg_file))
+
+        cur_date = datetime.datetime.now().isoformat(' ')
+        re_rev = re.compile(r'^rev\.', re.IGNORECASE)
+        re_trail_dot = re.compile(r'\.+$')
+
+        lines = []
+        lines.append('###############################################################')
+        lines.append('')
+        lines.append(' Bind9 configuration file for slave sones')
+        lines.append(' {}'.format(self.named_zones_cfg_file))
+        lines.append('')
+        lines.append(' Generated at: {}'.format(cur_date))
+        lines.append('')
+        lines.append('###############################################################')
+        header = textwrap.indent('\n'.join(lines), '//', lambda line: True) + '\n'
+
+        content = header
+
+        for zone in self.zones:
+
+            canonical_name = zone.name_unicode
+            match = self.re_ipv4_zone.search(zone.name)
+            if match:
+                prefix = self._get_ipv4_prefix(match.group(1))
+                if prefix:
+                    if prefix == '127.0.0':
+                        LOG.debug("Pure local zone {!r} will not be considered.".format(prefix))
+                        continue
+                    canonical_name = 'rev.' + prefix
+            else:
+                match = self.re_ipv6_zone.search(zone.name)
+                if match:
+                    prefix = self._get_ipv6_prefix(match.group(1))
+                    if prefix:
+                        canonical_name = 'rev.' + prefix
+
+            show_name = canonical_name
+            show_name = re_rev.sub('Reverse ', show_name)
+            show_name = re_trail_dot.sub('', show_name)
+            zname = re_trail_dot.sub('', zone.name)
+
+            zfile = os.path.join(
+                self.named_slavedir_rel, re_trail_dot.sub('', canonical_name) + '.zone')
+
+            lines = []
+            lines.append('')
+            lines.append('// {}'.format(show_name))
+            lines.append('zone "{}" in {{'.format(zname))
+            lines.append('\tmasters {')
+            for master in self.zone_masters:
+                lines.append('\t\t{};'.format(master))
+            lines.append('\t};')
+            lines.append('\ttype slave;')
+            lines.append('\tfile "{}";'.format(zfile))
+            lines.append('};')
+
+            content += '\n'.join(lines) + '\n'
+
+        content += '\n// vim: ts=8 filetype=named noet noai\n'
+
+        with open(self.temp_zones_cfg_file, 'w', **self.open_args) as fh:
+            fh.write(content)
+
+        if self.verbose > 2:
+            LOG.debug("Generated {!r}:\n{}".format(self.temp_zones_cfg_file, content.strip()))
+
+    # -------------------------------------------------------------------------
+    def _get_ipv4_prefix(self, match):
+
+        tuples = []
+        for t in match.split('.'):
+            if t:
+                tuples.insert(0, t)
+        if self.verbose > 2:
+            LOG.debug("Got IPv4 tuples: {}".format(pp(tuples)))
+        return '.'.join(tuples)
+
+    # -------------------------------------------------------------------------
+    def _get_ipv6_prefix(self, match):
+
+        tuples = []
+        for t in match.split('.'):
+            if t:
+                tuples.insert(0, t)
+
+        tokens = []
+        while len(tuples):
+            token = ''.join(tuples[0:4]).ljust(4, '0')
+            if token.startswith('000'):
+                token = token[3:]
+            elif token.startswith('00'):
+                token = token[2:]
+            elif token.startswith('0'):
+                token = token[1:]
+            tokens.append(token)
+            del tuples[0:4]
+
+        if self.verbose > 2:
+            LOG.debug("Got IPv6 tokens: {}".format(pp(tokens)))
+
+        return ':'.join(tokens)
+
 
 # =============================================================================
 
index 0d0654de744c7faae888e4287edddc5a2b52d4a9..fd6fe0731df9c6159a0de97d6b0ded323a6cd310 100644 (file)
@@ -26,7 +26,7 @@ from .common import pp, to_bool
 from .cfg_app import PpCfgAppError, PpConfigApplication
 from .pdns_zone import PdnsApiZone
 
-__version__ = '0.3.2'
+__version__ = '0.3.3'
 LOG = logging.getLogger(__name__)
 _LIBRARY_NAME = "pp-pdns-api-client"
 
@@ -546,7 +546,7 @@ class PpPDNSApplication(PpConfigApplication):
 
         path = "/servers/{}/zones".format(self.api_servername)
         json_response = self.perform_request(path)
-        if self.verbose > 2:
+        if self.verbose > 3:
             LOG.debug("Got a response:\n{}".format(pp(json_response)))
 
         zone_list = []
@@ -558,6 +558,9 @@ class PpPDNSApplication(PpConfigApplication):
             if self.verbose > 2:
                 print("{!r}".format(zone))
 
+        if self.verbose > 1:
+            LOG.debug("Found {} zones.".format(len(zone_list)))
+
         return zone_list
 
 # =============================================================================