Files
vacuum-wall/lib/dnsmasq.py
T
mteehan 8c13ad55ce Add update-vendor.sh symlink support, unify install.sh vendor flow
- update-vendor.sh now creates webui/vendor symlinks (htm.js)
- install.sh calls update-vendor.sh after package install
- Add vendor/.empty and webui/vendor/.empty as directory placeholders in git
2026-07-01 00:55:03 +00:00

81 lines
2.4 KiB
Python

"""Dnsmasq config persistence for Vacuum Wall.
Provides load/save for the declarative JSON config and upstream-management
helpers used by the sync bus and network handler. All mutation and
apply logic lives in daemon/handlers/dnsmasq.py.
"""
import logging
from copy import deepcopy
from pathlib import Path
from typing import Any
from lib.common import deep_merge, ensure_dirs, load_json, save_json
logger = logging.getLogger(__name__)
PROJECT_DIR = Path(__file__).resolve().parent.parent
CONFIG_DIR = PROJECT_DIR / "config" / "dnsmasq"
DATA_DIR = PROJECT_DIR / "data" / "dnsmasq"
CONFIG_PATH = CONFIG_DIR / "config.json"
FRAGMENTS_DIR = DATA_DIR / "fragments"
DEFAULT_CFG: dict[str, Any] = {
"dhcp": {
"ranges": [],
"static_leases": [],
},
"dns": {
"upstreams": ["8.8.8.8", "1.1.1.1"],
"domain": None,
"custom_records": [],
},
}
# ───────── config lifecycle ──────────────────────────────────────────
def get_config() -> dict[str, Any]:
"""Load current dnsmasq config from JSON state file."""
ensure_dirs(CONFIG_DIR, DATA_DIR, FRAGMENTS_DIR)
raw = load_json(CONFIG_PATH)
if not raw:
return deepcopy(DEFAULT_CFG)
return deep_merge(deepcopy(DEFAULT_CFG), raw)
def save_config(cfg: dict[str, Any]) -> None:
"""Persist config to JSON (does NOT touch on-disk dnsmasq config)."""
ensure_dirs(CONFIG_DIR, DATA_DIR, FRAGMENTS_DIR)
merged = deep_merge(deepcopy(DEFAULT_CFG), cfg)
save_json(CONFIG_PATH, merged)
logger.info("dnsmasq config saved")
# ───────── upstream helpers ──────────────────────────────────────────
def set_upstreams(servers: list[str]) -> None:
"""Set the list of upstream DNS forwarders."""
cfg = get_config()
cfg["dns"]["upstreams"] = list(servers)
save_config(cfg)
logger.info("DNS upstreams set to %s", servers)
def set_domain(domain: str | None) -> None:
"""Set (or clear) the local DNS domain."""
cfg = get_config()
cfg["dns"]["domain"] = domain if domain else None
save_config(cfg)
logger.info("DNS domain set to '%s'", domain)
__all__ = [
"get_config",
"save_config",
"set_domain",
"set_upstreams",
]