This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "IPFire 2.x development tree".
The branch, next has been updated
via 8ead2ddf3d0f1521c2a99b509373615f77a754a0 (commit)
from 048d2be91a17ea57b870b0b944d439978b2f88a8 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 8ead2ddf3d0f1521c2a99b509373615f77a754a0
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date: Wed Aug 21 10:10:33 2024 +0100
unbound-dhcp-leases-bridge: Watch unbound
This patch adds a watcher thread which monitors if Unbound is still
alive. If not, it will wait until Unbound comes back, rewrite the leases
file and reload Unbound to get it back into sync.
Afterwards Unbound will receive updates as usual.
Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>
-----------------------------------------------------------------------
Summary of changes:
config/unbound/unbound-dhcp-leases-bridge | 115 +++++++++++++++++++++++++++++-
1 file changed, 112 insertions(+), 3 deletions(-)
Difference in files:
diff --git a/config/unbound/unbound-dhcp-leases-bridge b/config/unbound/unbound-dhcp-leases-bridge
index 3972a45c6..986fae2d2 100644
--- a/config/unbound/unbound-dhcp-leases-bridge
+++ b/config/unbound/unbound-dhcp-leases-bridge
@@ -83,10 +83,10 @@ class UnboundDHCPLeasesBridge(object):
# Initialize the worker
self.worker = Worker(self.queue, callback=self._handle_message)
- self.unbound = UnboundConfigWriter(unbound_leases_file)
+ # Initialize the watcher
+ self.watcher = Watcher(reload=self.reload)
- # Load all required data
- self.reload()
+ self.unbound = UnboundConfigWriter(unbound_leases_file)
def run(self):
log.info("Unbound DHCP Leases Bridge started on %s" % self.leases_file)
@@ -94,6 +94,9 @@ class UnboundDHCPLeasesBridge(object):
# Launch the worker
self.worker.start()
+ # Launch the watcher
+ self.watcher.start()
+
# Open the server socket
self.socket = self._open_socket(self.socket_path)
@@ -132,7 +135,13 @@ class UnboundDHCPLeasesBridge(object):
# Terminate the worker
self.queue.put(None)
+
+ # Terminate the watcher
+ self.watcher.terminate()
+
+ # Wait for the worker and watcher to finish
self.worker.join()
+ self.watcher.join()
log.info("Unbound DHCP Leases Bridge terminated")
@@ -359,6 +368,84 @@ class UnboundDHCPLeasesBridge(object):
self.socket.close()
+class Watcher(threading.Thread):
+ """
+ Watches if Unbound is still running.
+ """
+ def __init__(self, reload, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+
+ self.reload = reload
+
+ # Set to true if this thread should be terminated
+ self._terminated = threading.Event()
+
+ def run(self):
+ log.debug("Watcher launched")
+
+ pidfd = None
+
+ while True:
+ # One iteration takes 30 seconds unless we don't know the process
+ # when we try to find it once a second.
+ if self._terminated.wait(30 if pidfd else 1):
+ break
+
+ # Fetch a PIDFD for Unbound
+ if pidfd is None:
+ pidfd = self._get_pidfd()
+
+ # If we could not acquire a PIDFD, we will try again soon...
+ if not pidfd:
+ log.warning("Cannot find Unbound...")
+ continue
+
+ # Since Unbound has been restarted, we need to reload it all...
+ self.reload()
+
+ log.debug("Checking if Unbound is still alive...")
+
+ # Send the process a signal
+ try:
+ signal.pidfd_send_signal(pidfd, signal.SIG_DFL)
+
+ # If the process has died, we land here and will have to wait until Unbound
+ # has come back and reload it...
+ except ProcessLookupError as e:
+ log.error("Unbound has died")
+
+ # Reset the PIDFD
+ pidfd = None
+
+ else:
+ log.debug("Unbound is alive")
+
+ log.debug("Watcher terminated")
+
+ def terminate(self):
+ """
+ Called to signal this thread to terminate
+ """
+ self._terminated.set()
+
+ def _get_pidfd(self):
+ """
+ Returns a PIDFD for unbound if it is running, otherwise None.
+ """
+ # Try to find the PID
+ pid = pidof("unbound")
+
+ if pid:
+ log.debug("Unbound is running as PID %s" % pid)
+
+ # Open a PIDFD
+ pidfd = os.pidfd_open(pid)
+
+ log.debug("Acquired PIDFD %s for PID %s" % (pidfd, pid))
+
+ return pidfd
+
+
class Worker(threading.Thread):
"""
The worker is launched in a separate thread
@@ -727,6 +814,28 @@ class UnboundConfigWriter(object):
self._control("local_data_remove", name)
+def pidof(program):
+ """
+ Returns the first PID of the given program.
+ """
+ try:
+ output = subprocess.check_output(["pidof", program])
+ except subprocess.CalledProcessError as e:
+ return
+
+ # Convert to string
+ output = output.decode()
+
+ # Return the first PID
+ for pid in output.split():
+ try:
+ pid = int(pid)
+ except ValueError:
+ continue
+
+ return pid
+
+
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Bridge for DHCP Leases and Unbound DNS")
hooks/post-receive
--
IPFire 2.x development tree