From mboxrd@z Thu Jan 1 00:00:00 1970 From: Michael Tremer <michael.tremer@ipfire.org> To: development@lists.ipfire.org Subject: Re: [PATCH 1/3] unbound-dhcp-leases-bridge : fix bug 12694 - DHCP hosts not reliably propagated to DNS Date: Tue, 29 Mar 2022 10:37:14 +0100 Message-ID: <3CA4B0BB-1D54-41D5-A069-61AFA9262647@ipfire.org> In-Reply-To: <349962CA-9202-427C-9D01-E1C5F7AE5764@gmail.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============4710843923513502903==" List-Id: <development.lists.ipfire.org> --===============4710843923513502903== Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Hello, This is indeed an absolute nightmare what I built here. It has some advantages over the alternatives of which one is to have the DHCP= server execute a couple of commands. The problems there are as follows: * unbound does not keep a state, so we will have to make sure that we keep th= e state of all records somewhere and can reload it when the system roboots. * I have installations with thousands of devices in a single subnet. The DHCP= server would just be busy constantly executing any commands which would caus= e a lot of load. The current Python bridge can use up to 40% of one CPU core = at busy times on the same system. I would argue that this approach does not s= cale well. * RFC2136 would be great, but we lack too many things to run this properly. That being said, this is not a great way to solve this problem. I would like = to replace some components entirely but probably not soon. The approach that = we have works and - apart from the bug - doesn=E2=80=99t suck too hard. Shoul= d we do it this way again? No, but we had to try to learn that lesson. -Michael > On 28 Mar 2022, at 20:32, Jon Murphy <jcmurphy26(a)gmail.com> wrote: >=20 > Sorry for interrupting this train of thought. Wouldn=E2=80=99t it be easie= r to use the tools available from dhcpd? >=20 > dhcpd seems to have a way execute commands. And I would guess this would b= e cleaner than "watching" a file. >=20 > There are three execute commands: > on commit > on release > on expiry >=20 > and these could be used to launch the needed unbound bridge command. >=20 > Here is where I found this: > https://jpmens.net/2011/07/06/execute-a-script-when-isc-dhcp-hands-out-a-ne= w-lease/ >=20 > And here is additional info: > https://wiki.samba.org/index.php/Configure_DHCP_to_update_DNS_records >=20 > (Search for "on commit" on this page) >=20 >=20 > Jon >=20 >=20 >> On Mar 28, 2022, at 12:00 PM, Michael Tremer <michael.tremer(a)ipfire.org>= wrote: >>=20 >> Hello Anthony, >>=20 >> Thank you very much for submitting this patch and welcome to the list. >>=20 >> I understand that it is easier to track any changes in the directory, but = I don=E2=80=99t quite understand why the logic had to be changed that the cha= nges will be applied at the end only. >>=20 >> Is this just to avoid that multiple updates happen one after the other or = what are you trying to achieve? >>=20 >> -Michael >>=20 >>> On 22 Mar 2022, at 03:47, Anthony Heading <ajrh(a)ajrh.net> wrote: >>>=20 >>> 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(-) >>>=20 >>> 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 =3D fix_leases_file >>> self.hosts_file =3D hosts_file >>>=20 >>> + # base mask for a completed file change >>> + mask =3D inotify.constants.IN_CLOSE_WRITE | inotify.constants.IN_MOVED= _TO >>> + # IN_MODIFY since dhcpd appends lease updates to an open file >>> + self.watches =3D { >>> + self.leases_file: mask | inotify.constants.IN_MODIFY, >>> + self.fix_leases_file: mask, >>> + self.hosts_file: mask >>> + } >>> + >>> self.unbound =3D UnboundConfigWriter(unbound_leases_file) >>> self.running =3D False >>>=20 >>> @@ -80,36 +89,42 @@ class UnboundDHCPLeasesBridge(object): >>> self.running =3D True >>>=20 >>> # Initial setup >>> - self.hosts =3D self.read_static_hosts() >>> - self.update_dhcp_leases() >>> + update_hosts =3D True >>> + update_leases =3D True >>> + >>> + i =3D inotify.adapters.Inotify() >>>=20 >>> - i =3D 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]) >>>=20 >>> for event in i.event_gen(): >>> # End if we are requested to terminate >>> if not self.running: >>> break >>>=20 >>> + # Make pending updates once inotify queue is empty >>> if event is None: >>> + if update_hosts: >>> + self.hosts =3D self.read_static_hosts() >>> + update_hosts =3D False >>> + if update_leases: >>> + self.update_dhcp_leases() >>> + update_leases =3D False >>> continue >>>=20 >>> header, type_names, watch_path, filename =3D event >>>=20 >>> - # Update leases after leases file has been modified >>> - if "IN_MODIFY" in type_names: >>> - # Reload hosts >>> - if watch_path =3D=3D self.hosts_file: >>> - self.hosts =3D self.read_static_hosts() >>> + file =3D os.path.join(watch_path, filename) >>> + >>> + if not file in self.watches: >>> + continue >>> + >>> + log.debug("Inotify %s: %s", file, " ".join(type_names)) >>>=20 >>> - self.update_dhcp_leases() >>> + update_leases =3D True >>>=20 >>> - # If the file is deleted, we re-add the watcher >>> - if "IN_IGNORED" in type_names: >>> - i.add_watch(watch_path) >>> + if file =3D=3D self.hosts_file: >>> + update_hosts =3D True >>>=20 >>> log.info("Unbound DHCP Leases Bridge terminated") >>>=20 >>> --=20 >>> 2.34.1 >>>=20 >>=20 >=20 --===============4710843923513502903==--