unbound-dhcp-leases-bridge: Reload unbound to import leases

This changes the old "diff" algorithm that we needed to have before
Unbound was able to reload its own configuration.

Now, it can do this even without dropping the cache. This should
hopefully perform much better and be more reliable than the old way.

Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
Acked-by: Peter Müller <peter.mueller@ipfire.org>
This commit is contained in:
Michael Tremer
2023-07-11 13:29:32 +00:00
committed by Peter Müller
parent 1b6b4118b2
commit f20ca78eff

View File

@@ -514,56 +514,19 @@ class UnboundConfigWriter(object):
def __init__(self, path): def __init__(self, path):
self.path = path self.path = path
self._cached_leases = []
def update_dhcp_leases(self, leases): def update_dhcp_leases(self, leases):
# Find any leases that have expired or do not exist any more
# but are still in the unbound local data
removed_leases = [l for l in self._cached_leases if not l in leases]
# Find any leases that have been added
new_leases = [l for l in leases if l not in self._cached_leases]
# End here if nothing has changed
if not new_leases and not removed_leases:
return
# Write out all leases # Write out all leases
self.write_dhcp_leases(leases) self.write_dhcp_leases(leases)
# Update unbound about changes log.debug("Reloading Unbound...")
for l in removed_leases:
try:
for name, ttl, type, content in l.rrset:
log.debug("Removing records for %s" % name)
self._control("local_data_remove", name)
# If the lease cannot be removed we will try the next one # Reload the configuration without dropping the cache
except: self._control("reload_keep_cache")
continue
# If the removal was successful, we will remove it from the cache
else:
self._cached_leases.remove(l)
for l in new_leases:
try:
for rr in l.rrset:
log.debug("Adding new record %s" % " ".join(rr))
self._control("local_data", *rr)
# If the lease cannot be added we will try the next one
except:
continue
# Add lease to cache when successfully added
else:
self._cached_leases.append(l)
def write_dhcp_leases(self, leases): def write_dhcp_leases(self, leases):
with tempfile.NamedTemporaryFile(mode="w", delete=False) as f: log.debug("Writing DHCP leases...")
filename = f.name
with tempfile.NamedTemporaryFile(mode="w", delete=False) as f:
for l in leases: for l in leases:
for rr in l.rrset: for rr in l.rrset:
f.write("local-data: \"%s\"\n" % " ".join(rr)) f.write("local-data: \"%s\"\n" % " ".join(rr))
@@ -571,7 +534,8 @@ class UnboundConfigWriter(object):
# Make file readable for everyone # Make file readable for everyone
os.fchmod(f.fileno(), stat.S_IRUSR|stat.S_IWUSR|stat.S_IRGRP|stat.S_IROTH) os.fchmod(f.fileno(), stat.S_IRUSR|stat.S_IWUSR|stat.S_IRGRP|stat.S_IROTH)
os.rename(filename, self.path) # Move the file to its destination
os.rename(f.name, self.path)
def _control(self, *args): def _control(self, *args):
command = ["unbound-control"] command = ["unbound-control"]
@@ -585,7 +549,7 @@ class UnboundConfigWriter(object):
log.critical("Could not run %s, error code: %s: %s" % ( log.critical("Could not run %s, error code: %s: %s" % (
" ".join(command), e.returncode, e.output)) " ".join(command), e.returncode, e.output))
raise raise e
if __name__ == "__main__": if __name__ == "__main__":