Switch from inotify watching individual files to monitoring the
containing directories, as because dhcpd renames its leases file into a
backup, monitoring the single inode does not work well. Additionally,
python appears to have a bug with replacing expired inotify watches on
single files.
---
unbound-dhcp-leases-bridge | 47 +++++++++++++++++++++++++-------------
1 file changed, 31 insertions(+), 16 deletions(-)
diff --git unbound-dhcp-leases-bridge unbound-dhcp-leases-bridge
index a2df5f1..6e22066 100644
--- unbound-dhcp-leases-bridge
+++ unbound-dhcp-leases-bridge
@@ -72,6 +72,15 @@ class UnboundDHCPLeasesBridge(object):
self.fix_leases_file = fix_leases_file
self.hosts_file = hosts_file
+ # base mask for a completed file change
+ mask = inotify.constants.IN_CLOSE_WRITE | inotify.constants.IN_MOVED_TO
+ # IN_MODIFY since dhcpd appends lease updates to an open file
+ self.watches = {
+ self.leases_file: mask | inotify.constants.IN_MODIFY,
+ self.fix_leases_file: mask,
+ self.hosts_file: mask
+ }
+
self.unbound = UnboundConfigWriter(unbound_leases_file)
self.running = False
@@ -80,36 +89,42 @@ class UnboundDHCPLeasesBridge(object):
self.running = True
# Initial setup
- self.hosts = self.read_static_hosts()
- self.update_dhcp_leases()
+ update_hosts = True
+ update_leases = True
+
+ i = inotify.adapters.Inotify()
- i = inotify.adapters.Inotify([
- self.leases_file,
- self.fix_leases_file,
- self.hosts_file,
- ])
+ for f in self.watches:
+ i.add_watch(os.path.dirname(f), self.watches[f])
for event in i.event_gen():
# End if we are requested to terminate
if not self.running:
break
+ # Make pending updates once inotify queue is empty
if event is None:
+ if update_hosts:
+ self.hosts = self.read_static_hosts()
+ update_hosts = False
+ if update_leases:
+ self.update_dhcp_leases()
+ update_leases = False
continue
header, type_names, watch_path, filename = event
- # Update leases after leases file has been modified
- if "IN_MODIFY" in type_names:
- # Reload hosts
- if watch_path == self.hosts_file:
- self.hosts = self.read_static_hosts()
+ file = os.path.join(watch_path, filename)
+
+ if not file in self.watches:
+ continue
+
+ log.debug("Inotify %s: %s", file, " ".join(type_names))
- self.update_dhcp_leases()
+ update_leases = True
- # If the file is deleted, we re-add the watcher
- if "IN_IGNORED" in type_names:
- i.add_watch(watch_path)
+ if file == self.hosts_file:
+ update_hosts = True
log.info("Unbound DHCP Leases Bridge terminated")
--
2.34.1