refactor: daemon collectors, thin webui proxies, pure config reads
- move state collectors from lib/state.py to daemon/collectors/ (7 modules, registration side-effect; daemon/server.py imports the package before the first populate()) - webui/api: new daemon_route() decorator factory in common.py collapses the try/except daemon-proxy boilerplate in all 8 blueprints (rules/params/body/transform keep responses identical) - firewall: interface-coverage invariant — config is the source of truth for zone interfaces (absent key = empty, no hands-off zones); pure validate_coverage() enforced at save (400) and apply (409, force: true overrides), top-level `unmanaged` exemption - lib: get_config() reads are now pure (no dir creation or writes); new lib/bootstrap.py creates runtime dirs and persists the one-shot nginx legacy migration at daemon start, after system_import (lib.nginx.migrate_config_file) - lib/common: compute_pending() apply-bookkeeping helper - daemon: emit_and_refresh() handler helper; refresh_state(bump=) so /status/refresh no longer bumps versions (poll/mutation only) - acme: move --log last so acme.sh never treats a real arg as the log-file argument - docs: AGENTS.md, config.md, state-model.md, api.md updated; HARDEN.md dropped (plan implemented); apply-confirm force wording Tests: 917 passed; ruff check + format clean.
This commit is contained in:
@@ -5,6 +5,7 @@ import os
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from daemon.handlers.common import emit_and_refresh
|
||||
from daemon.iface import (
|
||||
DELETE_WIREGUARD_CLASSES,
|
||||
DELETE_WIREGUARD_CLASSES_DOWN,
|
||||
@@ -27,9 +28,8 @@ from daemon.iface import (
|
||||
POST_WIREGUARD_INITIALIZE,
|
||||
POST_WIREGUARD_PEERS_ADD,
|
||||
)
|
||||
from daemon.server import ConflictError, NotFoundError, refresh_state, registry
|
||||
from daemon.server import ConflictError, NotFoundError, registry
|
||||
from lib.common import deep_merge, run, stamp_applied, strip_apply_meta
|
||||
from lib.sync import SyncEvent, bus
|
||||
from lib.wireguard import (
|
||||
_class_interface_name,
|
||||
_class_peers,
|
||||
@@ -122,10 +122,7 @@ def save_config_handler(_request: Any, body: dict[str, Any] | None) -> dict[str,
|
||||
body["access_classes"] = current.get("access_classes", {})
|
||||
|
||||
_save_wireguard_config(body)
|
||||
sync_result = bus.emit(
|
||||
SyncEvent("wireguard", "config_saved", {"action": "config_saved"})
|
||||
)
|
||||
refresh_state(["wireguard", *sync_result.affected_subsystems])
|
||||
emit_and_refresh("wireguard", {"action": "config_saved"})
|
||||
return {"config_saved": True}
|
||||
|
||||
|
||||
@@ -153,10 +150,7 @@ def patch_config(_request: Any, body: dict[str, Any] | None) -> dict[str, Any]:
|
||||
current = _get_wireguard_config()
|
||||
merged = deep_merge(current, body)
|
||||
_save_wireguard_config(merged)
|
||||
sync_result = bus.emit(
|
||||
SyncEvent("wireguard", "config_saved", {"action": "config_patched"})
|
||||
)
|
||||
refresh_state(["wireguard", *sync_result.affected_subsystems])
|
||||
emit_and_refresh("wireguard", {"action": "config_patched"})
|
||||
return {"config_saved": True}
|
||||
|
||||
|
||||
@@ -217,13 +211,10 @@ def apply(_request: Any, _body: Any) -> dict[str, Any]:
|
||||
cfg_after = _get_wireguard_config()
|
||||
stamp_applied(cfg_after)
|
||||
_save_wireguard_config(cfg_after)
|
||||
sync_result = bus.emit(
|
||||
SyncEvent("wireguard", "config_saved", {"action": "config_applied"})
|
||||
)
|
||||
refresh_state(["wireguard", *sync_result.affected_subsystems])
|
||||
synced = emit_and_refresh("wireguard", {"action": "config_applied"})
|
||||
return {
|
||||
"applied": True,
|
||||
"synced": sync_result.affected_subsystems,
|
||||
"synced": synced,
|
||||
"interfaces": affected,
|
||||
}
|
||||
|
||||
@@ -255,10 +246,7 @@ def down(_request: Any, _body: Any) -> dict[str, Any]:
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
sync_result = bus.emit(
|
||||
SyncEvent("wireguard", "config_saved", {"action": "tunnel_down"})
|
||||
)
|
||||
refresh_state(["wireguard", *sync_result.affected_subsystems])
|
||||
emit_and_refresh("wireguard", {"action": "tunnel_down"})
|
||||
return {"down": True}
|
||||
|
||||
|
||||
@@ -296,12 +284,7 @@ def class_up(_request: Any, body: dict[str, Any] | None) -> dict[str, Any]:
|
||||
local_tmp.unlink(missing_ok=True)
|
||||
run([WG_QUICK_BIN, "up", ifname], sudo=True, check=False)
|
||||
logger.info("WireGuard class '%s' tunnel '%s' brought up", class_key, ifname)
|
||||
sync_result = bus.emit(
|
||||
SyncEvent(
|
||||
"wireguard", "config_saved", {"action": "class_up", "class_key": class_key}
|
||||
)
|
||||
)
|
||||
refresh_state(["wireguard", *sync_result.affected_subsystems])
|
||||
emit_and_refresh("wireguard", {"action": "class_up", "class_key": class_key})
|
||||
return {"up": True, "interface": ifname}
|
||||
|
||||
|
||||
@@ -328,14 +311,7 @@ def class_down(_request: Any, body: dict[str, Any] | None) -> dict[str, Any]:
|
||||
logger.info("WireGuard class '%s' tunnel '%s' brought down", class_key, ifname)
|
||||
except Exception:
|
||||
pass
|
||||
sync_result = bus.emit(
|
||||
SyncEvent(
|
||||
"wireguard",
|
||||
"config_saved",
|
||||
{"action": "class_down", "class_key": class_key},
|
||||
)
|
||||
)
|
||||
refresh_state(["wireguard", *sync_result.affected_subsystems])
|
||||
emit_and_refresh("wireguard", {"action": "class_down", "class_key": class_key})
|
||||
return {"down": True, "interface": ifname}
|
||||
|
||||
|
||||
@@ -377,10 +353,7 @@ def initialize(_request: Any, _body: Any) -> dict[str, Any]:
|
||||
|
||||
_save_wireguard_config(cfg)
|
||||
logger.info("WireGuard initialised (pubkey=%s...)", pub[:16])
|
||||
sync_result = bus.emit(
|
||||
SyncEvent("wireguard", "config_saved", {"action": "initialized"})
|
||||
)
|
||||
refresh_state(["wireguard", *sync_result.affected_subsystems])
|
||||
emit_and_refresh("wireguard", {"action": "initialized"})
|
||||
|
||||
safe = dict(cfg)
|
||||
safe["interface"] = dict(safe["interface"])
|
||||
@@ -467,12 +440,7 @@ def add_peer(_request: Any, body: dict[str, Any] | None) -> dict[str, Any]:
|
||||
logger.info("WireGuard peer '%s' added", name)
|
||||
_peer_action = "peer_added"
|
||||
_save_wireguard_config(cfg)
|
||||
sync_result = bus.emit(
|
||||
SyncEvent(
|
||||
"wireguard", "config_saved", {"action": _peer_action, "peer_name": name}
|
||||
)
|
||||
)
|
||||
refresh_state(["wireguard", *sync_result.affected_subsystems])
|
||||
emit_and_refresh("wireguard", {"action": _peer_action, "peer_name": name})
|
||||
peer_out = dict(peers[name])
|
||||
peer_out.pop("private_key", None)
|
||||
return peer_out
|
||||
@@ -498,12 +466,7 @@ def remove_peer(_request: Any, body: dict[str, Any] | None) -> dict[str, Any]:
|
||||
del peers[name]
|
||||
_save_wireguard_config(cfg)
|
||||
logger.info("WireGuard peer '%s' removed", name)
|
||||
sync_result = bus.emit(
|
||||
SyncEvent(
|
||||
"wireguard", "config_saved", {"action": "peer_removed", "peer_name": name}
|
||||
)
|
||||
)
|
||||
refresh_state(["wireguard", *sync_result.affected_subsystems])
|
||||
emit_and_refresh("wireguard", {"action": "peer_removed", "peer_name": name})
|
||||
return {"name": name}
|
||||
|
||||
|
||||
@@ -629,10 +592,7 @@ def create_class(_request: Any, body: dict[str, Any] | None) -> dict[str, Any]:
|
||||
"public_key": "",
|
||||
}
|
||||
_save_wireguard_config(cfg)
|
||||
sync_result = bus.emit(
|
||||
SyncEvent("wireguard", "config_saved", {"action": "class_created"})
|
||||
)
|
||||
refresh_state(["wireguard", *sync_result.affected_subsystems])
|
||||
emit_and_refresh("wireguard", {"action": "class_created"})
|
||||
out = dict(classes[key])
|
||||
out.pop("private_key", None)
|
||||
return out
|
||||
@@ -660,10 +620,7 @@ def update_class(_request: Any, body: dict[str, Any] | None) -> dict[str, Any]:
|
||||
if field in body:
|
||||
class_cfg[field] = body[field]
|
||||
_save_wireguard_config(cfg)
|
||||
sync_result = bus.emit(
|
||||
SyncEvent("wireguard", "config_saved", {"action": "class_updated"})
|
||||
)
|
||||
refresh_state(["wireguard", *sync_result.affected_subsystems])
|
||||
emit_and_refresh("wireguard", {"action": "class_updated"})
|
||||
out = dict(classes[key])
|
||||
out.pop("private_key", None)
|
||||
return {"key": key, **out}
|
||||
@@ -699,8 +656,5 @@ def delete_class(_request: Any, body: dict[str, Any] | None) -> dict[str, Any]:
|
||||
)
|
||||
del classes[key]
|
||||
_save_wireguard_config(cfg)
|
||||
sync_result = bus.emit(
|
||||
SyncEvent("wireguard", "config_saved", {"action": "class_deleted"})
|
||||
)
|
||||
refresh_state(["wireguard", *sync_result.affected_subsystems])
|
||||
emit_and_refresh("wireguard", {"action": "class_deleted"})
|
||||
return {"key": key}
|
||||
|
||||
Reference in New Issue
Block a user