link and flake cleanup

This commit is contained in:
2026-02-08 16:05:03 -05:00
parent 087a264e97
commit 5e6dfc75ad
24 changed files with 393 additions and 186 deletions
+66 -13
View File
@@ -1,13 +1,23 @@
"""DNS update helper and pure asyncio worker for heartbeat daemon."""
from __future__ import annotations
import subprocess
from subprocess import Popen, PIPE, STDOUT
from typing import Optional
import asyncio
def create_nsupdate_payload(hostname: str, newip: str, dyndomain: str, dnsttl: str = "5") -> str:
D = {"domain": dyndomain, "fqdn": f"{hostname}.dy.{dyndomain}", "dnsttl": dnsttl, "newip": newip, "ts": __import__("time").strftime("%Y-%m-%d.%H:%M:%S", __import__("time").gmtime())}
def create_nsupdate_payload(
hostname: str, newip: str, dyndomain: str, dnsttl: str = "5"
) -> str:
D = {
"domain": dyndomain,
"fqdn": f"{hostname}.dy.{dyndomain}",
"dnsttl": dnsttl,
"newip": newip,
"ts": __import__("time").strftime(
"%Y-%m-%d.%H:%M:%S", __import__("time").gmtime()
),
}
if ":" in newip:
nsup = (
"""update delete %(fqdn)s AAAA
@@ -17,7 +27,8 @@ update add %(fqdn)s %(dnsttl)s TXT "Created: %(ts)s"
send
answer
""" % D
"""
% D
)
else:
nsup = (
@@ -28,12 +39,19 @@ update add %(fqdn)s %(dnsttl)s TXT "Created: %(ts)s"
send
answer
""" % D
"""
% D
)
return nsup
def nsupdate(hostname: str, newip: str, dyndomain: str, nsupdate_bin: str = "/usr/local/bin/nsupdate", rndc_key: str = "/etc/dhcpc/rndc-key") -> Optional[str]:
def nsupdate(
hostname: str,
newip: str,
dyndomain: str,
nsupdate_bin: str = "/usr/local/bin/nsupdate",
rndc_key: str = "/etc/dhcpc/rndc-key",
) -> Optional[str]:
"""Perform DNS update via nsupdate command.
Returns None on success, else returns combined stdout/stderr as a string.
@@ -54,7 +72,14 @@ def nsupdate(hostname: str, newip: str, dyndomain: str, nsupdate_bin: str = "/us
return out
async def dns_update_worker(hbdclass, cfg: dict, async_queue=None, log: Optional[callable] = None, pushmsg: Optional[callable] = None, loop: Optional[asyncio.AbstractEventLoop] = None):
async def dns_update_worker(
hbdclass,
cfg: dict,
async_queue=None,
log: Optional[callable] = None,
pushmsg: Optional[callable] = None,
loop: Optional[asyncio.AbstractEventLoop] = None,
):
"""Pure async DNS worker that processes updates from asyncio.Queue.
Exits when it receives a None sentinel.
@@ -66,7 +91,9 @@ async def dns_update_worker(hbdclass, cfg: dict, async_queue=None, log: Optional
if not dnsq:
if log:
try:
await loop.run_in_executor(None, log, None, "dns_update_worker: no queue available")
await loop.run_in_executor(
None, log, None, "dns_update_worker: no queue available"
)
except Exception:
pass
return
@@ -77,7 +104,9 @@ async def dns_update_worker(hbdclass, cfg: dict, async_queue=None, log: Optional
except Exception as e:
if log:
try:
await loop.run_in_executor(None, log, None, f"dns_update_worker: error getting item: {e}")
await loop.run_in_executor(
None, log, None, f"dns_update_worker: error getting item: {e}"
)
except Exception:
pass
break
@@ -96,12 +125,25 @@ async def dns_update_worker(hbdclass, cfg: dict, async_queue=None, log: Optional
m = f"changed address to {addr}"
for dyndomain in cfg.get("dyndomains", []):
err = await loop.run_in_executor(None, nsupdate, name, addr, dyndomain, cfg.get("nsupdate_bin", "/usr/local/bin/nsupdate"), cfg.get("rndc_key", "/etc/dhcpc/rndc-key"))
err = await loop.run_in_executor(
None,
nsupdate,
name,
addr,
dyndomain,
cfg.get("nsupdate_bin", "/usr/local/bin/nsupdate"),
cfg.get("rndc_key", "/etc/dhcpc/rndc-key"),
)
if err:
m += f", DNS update failed: {err}"
if pushmsg:
try:
await loop.run_in_executor(None, pushmsg, "error: nsupdate failed", f"{name}.dy.{dyndomain}: {m}")
await loop.run_in_executor(
None,
pushmsg,
"error: nsupdate failed",
f"{name}.dy.{dyndomain}: {m}",
)
except Exception:
pass
else:
@@ -125,7 +167,13 @@ async def dns_update_worker(hbdclass, cfg: dict, async_queue=None, log: Optional
pass
def start_dns_worker(hbdclass, cfg: dict, log: Optional[callable] = None, pushmsg: Optional[callable] = None, loop: Optional[asyncio.AbstractEventLoop] = None):
def start_dns_worker(
hbdclass,
cfg: dict,
log: Optional[callable] = None,
pushmsg: Optional[callable] = None,
loop: Optional[asyncio.AbstractEventLoop] = None,
):
"""Start the async DNS worker and return the Task.
Replaces Host.dnsQ with an asyncio.Queue wrapped in a thread-safe bridge
@@ -139,6 +187,7 @@ def start_dns_worker(hbdclass, cfg: dict, log: Optional[callable] = None, pushms
class _QueueBridge:
"""Thread-safe wrapper around asyncio.Queue for synchronous callers."""
def __init__(self, loop, aq):
self._loop = loop
self._aq = aq
@@ -167,5 +216,9 @@ def start_dns_worker(hbdclass, cfg: dict, log: Optional[callable] = None, pushms
bridge = _QueueBridge(loop, async_q)
hbdclass.Host.dnsQ = bridge
task = loop.create_task(dns_update_worker(hbdclass, cfg, async_queue=async_q, log=log, pushmsg=pushmsg, loop=loop))
task = loop.create_task(
dns_update_worker(
hbdclass, cfg, async_queue=async_q, log=log, pushmsg=pushmsg, loop=loop
)
)
return task