]> Frank Brehm's Git Trees - pixelpark/admin-tools.git/commitdiff
Applying configuration and reloading BIND
authorFrank Brehm <frank.brehm@pixelpark.com>
Fri, 10 Nov 2017 09:30:02 +0000 (10:30 +0100)
committerFrank Brehm <frank.brehm@pixelpark.com>
Fri, 10 Nov 2017 09:30:02 +0000 (10:30 +0100)
pp_lib/deploy_zones_from_pdns.py

index 611a5c169eee66affca19fdc32aae9c822eddfeb..7ca8579d7fa744fdb8ef895a8100f72f69bece83 100644 (file)
@@ -20,6 +20,7 @@ import socket
 import tempfile
 import time
 import shutil
+import pipes
 
 from subprocess import Popen, TimeoutExpired, PIPE
 
@@ -43,7 +44,7 @@ from .pdns_record import compare_rrsets
 
 from .pidfile import PidFileError, InvalidPidFileError, PidFileInUseError, PidFile
 
-__version__ = '0.3.2'
+__version__ = '0.4.1'
 LOG = logging.getLogger(__name__)
 
 
@@ -331,6 +332,16 @@ class PpDeployZonesApp(PpPDNSApplication):
             self.generate_slave_cfg_file()
             self.compare_files()
 
+            try:
+                self.replace_configfiles()
+                if not self.check_namedconf():
+                    self.restore_configfiles()
+                    self.exit(99)
+                self.apply_config()
+            except Exception:
+                self.restore_configfiles()
+                raise
+
         finally:
             self.cleanup()
             self.pidfile = None
@@ -568,6 +579,245 @@ class PpDeployZonesApp(PpPDNSApplication):
 
         return True
 
+    # -------------------------------------------------------------------------
+    def replace_configfiles(self):
+
+        if not self.files2replace:
+            LOG.debug("No replacement of any config files necessary.")
+            return
+
+        LOG.debug("Start replacing of config files ...")
+
+        for tgt_file in self.files2replace.keys():
+
+            backup_file = tgt_file + self.backup_suffix
+
+            if os.path.exists(tgt_file):
+                self.moved_files[tgt_file] = backup_file
+                LOG.info("Copying {!r} => {!r} ...".format(tgt_file, backup_file))
+                if not self.simulate:
+                    shutil.copy2(tgt_file, backup_file)
+
+        if self.verbose > 1:
+            LOG.debug("All backuped config files:\n{}".format(pp(self.moved_files)))
+
+        for tgt_file in self.files2replace.keys():
+            src_file = self.files2replace[tgt_file]
+            LOG.info("Copying {!r} => {!r} ...".format(src_file, tgt_file))
+            if not self.simulate:
+                shutil.copy2(src_file, tgt_file)
+
+    # -------------------------------------------------------------------------
+    def restore_configfiles(self):
+
+        LOG.error("Restoring of original config files because of an exception.")
+
+        for tgt_file in self.moved_files.keys():
+            backup_file = self.moved_files[tgt_file]
+            LOG.info("Moving {!r} => {!r} ...".format(backup_file, tgt_file))
+            if not self.simulate:
+                if os.path.exists(backup_file):
+                    os.rename(backup_file, tgt_file)
+                else:
+                    LOG.error("Could not find backup file {!r}.".format(backup_file))
+
+    # -------------------------------------------------------------------------
+    def check_namedconf(self):
+
+        LOG.info("Checking syntax correctness of named.conf ...")
+        cmd = shlex.split(self.cmd_checkconf)
+        if 'named-checkconf' in self.cmd_checkconf and self.verbose > 2:
+            cmd.append('-p')
+        cmd_str = ' '.join(map(lambda x: pipes.quote(x), cmd))
+        LOG.debug("Executing: {}".format(cmd_str))
+
+        std_out = None
+        std_err = None
+        ret_val = None
+
+        with Popen(cmd, stdout=PIPE, stderr=PIPE) as proc:
+            try:
+                std_out, std_err = proc.communicate(timeout=10)
+            except TimeoutExpired:
+                proc.kill()
+                std_out, std_err = proc.communicate()
+            ret_val = proc.wait()
+
+        LOG.debug("Return value: {!r}".format(ret_val))
+        if std_out and std_out.strip():
+            s = to_str(std_out.strip())
+            LOG.warn("Output on STDOUT: {}".format(s))
+        if std_err and std_err.strip():
+            s = to_str(std_err.strip())
+            LOG.warn("Output on STDERR: {}".format(s))
+
+        if ret_val:
+            return False
+
+        return True
+
+    # -------------------------------------------------------------------------
+    def apply_config(self):
+
+        if not self.reload_necessary and not self.restart_necessary:
+            LOG.info("Reload or restart of named is not necessary.")
+            return
+
+        running = self.named_running()
+        if not running:
+            LOG.warn("Named is not running, please start it manually.")
+            return
+
+        if self.restart_necessary:
+            self.restart_named()
+        else:
+            self.reload_named()
+
+    # -------------------------------------------------------------------------
+    def named_running(self):
+
+        LOG.debug("Checking, whether named is running ...")
+
+        cmd = shlex.split(self.cmd_status)
+        cmd_str = ' '.join(map(lambda x: pipes.quote(x), cmd))
+        LOG.debug("Executing: {}".format(cmd_str))
+
+        std_out = None
+        std_err = None
+        ret_val = None
+
+        with Popen(cmd, stdout=PIPE, stderr=PIPE) as proc:
+            try:
+                std_out, std_err = proc.communicate(timeout=10)
+            except TimeoutExpired:
+                proc.kill()
+                std_out, std_err = proc.communicate()
+            ret_val = proc.wait()
+
+        LOG.debug("Return value: {!r}".format(ret_val))
+        if std_out and std_out.strip():
+            s = to_str(std_out.strip())
+            LOG.debug("Output on STDOUT:\n{}".format(s))
+        if std_err and std_err.strip():
+            s = to_str(std_err.strip())
+            LOG.warn("Output on STDERR: {}".format(s))
+
+        if ret_val:
+            return False
+
+        return True
+
+    # -------------------------------------------------------------------------
+    def start_named(self):
+
+        LOG.info("Starting named ...")
+
+        cmd = shlex.split(self.cmd_start)
+        cmd_str = ' '.join(map(lambda x: pipes.quote(x), cmd))
+        LOG.debug("Executing: {}".format(cmd_str))
+
+        if self.simulate:
+            return
+
+        std_out = None
+        std_err = None
+        ret_val = None
+
+        with Popen(cmd, stdout=PIPE, stderr=PIPE) as proc:
+            try:
+                std_out, std_err = proc.communicate(timeout=30)
+            except TimeoutExpired:
+                proc.kill()
+                std_out, std_err = proc.communicate()
+            ret_val = proc.wait()
+
+        LOG.debug("Return value: {!r}".format(ret_val))
+        if std_out and std_out.strip():
+            s = to_str(std_out.strip())
+            LOG.debug("Output on STDOUT:\n{}".format(s))
+        if std_err and std_err.strip():
+            s = to_str(std_err.strip())
+            LOG.error("Output on STDERR: {}".format(s))
+
+        if ret_val:
+            return False
+
+        return True
+
+    # -------------------------------------------------------------------------
+    def restart_named(self):
+
+        LOG.info("Restarting named ...")
+
+        cmd = shlex.split(self.cmd_restart)
+        cmd_str = ' '.join(map(lambda x: pipes.quote(x), cmd))
+        LOG.debug("Executing: {}".format(cmd_str))
+
+        if self.simulate:
+            return
+
+        std_out = None
+        std_err = None
+        ret_val = None
+
+        with Popen(cmd, stdout=PIPE, stderr=PIPE) as proc:
+            try:
+                std_out, std_err = proc.communicate(timeout=30)
+            except TimeoutExpired:
+                proc.kill()
+                std_out, std_err = proc.communicate()
+            ret_val = proc.wait()
+
+        LOG.debug("Return value: {!r}".format(ret_val))
+        if std_out and std_out.strip():
+            s = to_str(std_out.strip())
+            LOG.debug("Output on STDOUT:\n{}".format(s))
+        if std_err and std_err.strip():
+            s = to_str(std_err.strip())
+            LOG.error("Output on STDERR: {}".format(s))
+
+        if ret_val:
+            return False
+
+        return True
+
+    # -------------------------------------------------------------------------
+    def reload_named(self):
+
+        LOG.info("Reloading named ...")
+
+        cmd = shlex.split(self.cmd_reload)
+        cmd_str = ' '.join(map(lambda x: pipes.quote(x), cmd))
+        LOG.debug("Executing: {}".format(cmd_str))
+
+        if self.simulate:
+            return
+
+        std_out = None
+        std_err = None
+        ret_val = None
+
+        with Popen(cmd, stdout=PIPE, stderr=PIPE) as proc:
+            try:
+                std_out, std_err = proc.communicate(timeout=30)
+            except TimeoutExpired:
+                proc.kill()
+                std_out, std_err = proc.communicate()
+            ret_val = proc.wait()
+
+        LOG.debug("Return value: {!r}".format(ret_val))
+        if std_out and std_out.strip():
+            s = to_str(std_out.strip())
+            LOG.debug("Output on STDOUT:\n{}".format(s))
+        if std_err and std_err.strip():
+            s = to_str(std_err.strip())
+            LOG.error("Output on STDERR: {}".format(s))
+
+        if ret_val:
+            return False
+
+        return True
+
 
 # =============================================================================