fix: run full reload after HTTP config publish, not just config.reload()

HTTP config-mutating endpoints (publish, rollback, channel CRUD, user
self-update) were calling config.reload() directly, which only refreshed
the in-memory config dict. This skipped re-applying host.dyn/host.watched
flags to live Host objects, so enabling dyndns via the UI had no effect
until a SIGHUP was sent.

Wire a reload_callback through http.start() that calls the same
reload_configuration() function used by the SIGHUP handler, ensuring
host attributes, notify module, users, and threshold checker are all
updated on every config publish.

Also fix unmatched quote in udp.py f-string log message.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Andreas Wrede
2026-05-12 15:05:52 -04:00
parent a00282913b
commit 817ae064af
3 changed files with 27 additions and 10 deletions
+19 -6
View File
@@ -264,6 +264,7 @@ async def start(
get_now=None, get_now=None,
VER="", VER="",
threshold_checker=None, threshold_checker=None,
reload_callback=None,
): ):
"""Start an aiohttp web server and block until cancelled. """Start an aiohttp web server and block until cancelled.
@@ -1319,7 +1320,9 @@ async def start(
logger.error("Config write failed: %s", exc) logger.error("Config write failed: %s", exc)
return web.json_response({"error": str(exc)}, status=500) return web.json_response({"error": str(exc)}, status=500)
if hasattr(config, "reload"): if reload_callback:
await reload_callback()
elif hasattr(config, "reload"):
await config.reload() await config.reload()
users_mod.load_users(config) users_mod.load_users(config)
@@ -1350,7 +1353,9 @@ async def start(
logger.error("Rollback failed: %s", exc) logger.error("Rollback failed: %s", exc)
return web.json_response({"error": str(exc)}, status=500) return web.json_response({"error": str(exc)}, status=500)
if hasattr(config, "reload"): if reload_callback:
await reload_callback()
elif hasattr(config, "reload"):
await config.reload() await config.reload()
users_mod.load_users(config) users_mod.load_users(config)
@@ -1474,7 +1479,9 @@ async def start(
logger.error("Channel create failed: %s", exc) logger.error("Channel create failed: %s", exc)
return web.json_response({"error": str(exc)}, status=500) return web.json_response({"error": str(exc)}, status=500)
if hasattr(config, "reload"): if reload_callback:
await reload_callback()
elif hasattr(config, "reload"):
await config.reload() await config.reload()
return web.json_response({"ok": True, "name": name}) return web.json_response({"ok": True, "name": name})
@@ -1540,7 +1547,9 @@ async def start(
logger.error("Channel update failed: %s", exc) logger.error("Channel update failed: %s", exc)
return web.json_response({"error": str(exc)}, status=500) return web.json_response({"error": str(exc)}, status=500)
if hasattr(config, "reload"): if reload_callback:
await reload_callback()
elif hasattr(config, "reload"):
await config.reload() await config.reload()
return web.json_response({"ok": True}) return web.json_response({"ok": True})
@@ -1572,7 +1581,9 @@ async def start(
logger.error("Channel delete failed: %s", exc) logger.error("Channel delete failed: %s", exc)
return web.json_response({"error": str(exc)}, status=500) return web.json_response({"error": str(exc)}, status=500)
if hasattr(config, "reload"): if reload_callback:
await reload_callback()
elif hasattr(config, "reload"):
await config.reload() await config.reload()
return web.json_response({"ok": True}) return web.json_response({"ok": True})
@@ -1631,7 +1642,9 @@ async def start(
logger.error("User self-update failed: %s", exc) logger.error("User self-update failed: %s", exc)
return web.json_response({"error": str(exc)}, status=500) return web.json_response({"error": str(exc)}, status=500)
if hasattr(config, "reload"): if reload_callback:
await reload_callback()
elif hasattr(config, "reload"):
await config.reload() await config.reload()
users_mod.load_users(config) users_mod.load_users(config)
+4
View File
@@ -242,6 +242,9 @@ async def _run_async(config, config_path=None):
# upgrade or config change between runs). # upgrade or config change between runs).
threshold_checker.purge_stale_alerts(hbdclass) threshold_checker.purge_stale_alerts(hbdclass)
async def _http_reload_callback():
await reload_configuration(config, config_path, components)
# HTTP server (asyncio-based via aiohttp) # HTTP server (asyncio-based via aiohttp)
try: try:
http_task = asyncio.create_task( http_task = asyncio.create_task(
@@ -255,6 +258,7 @@ async def _run_async(config, config_path=None):
verbose=config.get("verbose", False), verbose=config.get("verbose", False),
get_now=lambda: time.time(), get_now=lambda: time.time(),
VER="", VER="",
reload_callback=_http_reload_callback,
) )
) )
logger.info( logger.info(
+1 -1
View File
@@ -377,7 +377,7 @@ def handle_datagram(msg: dict, addr, transport, ctx: dict):
default_owner = config_mod.get_default_owner(cfg) default_owner = config_mod.get_default_owner(cfg)
inferred_owner = plugin_data.get("owner", config_owner or default_owner) inferred_owner = plugin_data.get("owner", config_owner or default_owner)
host.owner = inferred_owner host.owner = inferred_owner
logger.info(f"owner for {uname} is '{host.owner}") logger.info(f"owner for {uname} is {host.owner}")
if DEBUG > 1: if DEBUG > 1:
print(f"Stored plugin data for {uname}: {plugin_name}") print(f"Stored plugin data for {uname}: {plugin_name}")