docs: add docstrings to all API endpoints and daemon handlers
Add comprehensive docstrings to firewall, DHCP, proxy, wireguard, certs, and logs API endpoints. Document parameters, return values, and error cases for the documentation system.
This commit is contained in:
@@ -42,20 +42,24 @@ DEFAULT_CONFIG: dict[str, Any] = {
|
||||
|
||||
|
||||
def _get_state() -> dict[str, Any] | None:
|
||||
"""Retrieve cached WireGuard state from the global state store."""
|
||||
from lib.state import state as state_store
|
||||
|
||||
return state_store.get("wireguard")
|
||||
|
||||
|
||||
def _get_config() -> dict[str, Any]:
|
||||
"""Load and merge the WireGuard config with defaults."""
|
||||
return deep_merge(deepcopy(DEFAULT_CONFIG), load_json(CONFIG_PATH))
|
||||
|
||||
|
||||
def _save_config(cfg: dict[str, Any]) -> None:
|
||||
"""Persist the WireGuard config to disk."""
|
||||
save_json(CONFIG_PATH, cfg)
|
||||
|
||||
|
||||
def _generate_conf(cfg: dict[str, Any]) -> str:
|
||||
"""Render the WireGuard server config file from Jinja template."""
|
||||
tmpl = ENV.get_template("wireguard.conf")
|
||||
return tmpl.render(
|
||||
timestamp=datetime.now(UTC).strftime("%Y-%m-%dT%H:%M:%SZ"),
|
||||
@@ -65,6 +69,7 @@ def _generate_conf(cfg: dict[str, Any]) -> str:
|
||||
|
||||
|
||||
def _get_wg_state() -> dict[str, Any]:
|
||||
"""Return cached WireGuard state, or empty dict if not yet loaded."""
|
||||
wg = _get_state()
|
||||
if wg is None:
|
||||
return {}
|
||||
@@ -77,6 +82,7 @@ def _get_wg_state() -> dict[str, Any]:
|
||||
|
||||
@registry.register("GET", "/wireguard/config")
|
||||
def get_config(_request: Any, _body: Any) -> dict[str, Any]:
|
||||
"""GET /wireguard/config — return WireGuard config with private key stripped."""
|
||||
wg = _get_wg_state()
|
||||
if wg:
|
||||
return wg.get("config", {})
|
||||
@@ -90,6 +96,11 @@ def get_config(_request: Any, _body: Any) -> dict[str, Any]:
|
||||
|
||||
@registry.register("POST", "/wireguard/config")
|
||||
def save_config_handler(_request: Any, body: dict[str, Any] | None) -> dict[str, Any]:
|
||||
"""POST /wireguard/config — replace config, preserving existing private key.
|
||||
|
||||
Raises:
|
||||
ValueError: When request body is missing.
|
||||
"""
|
||||
if not body:
|
||||
raise ValueError("Request body required")
|
||||
current = _get_config()
|
||||
@@ -107,6 +118,11 @@ def save_config_handler(_request: Any, body: dict[str, Any] | None) -> dict[str,
|
||||
|
||||
@registry.register("PATCH", "/wireguard/config")
|
||||
def patch_config(_request: Any, body: dict[str, Any] | None) -> dict[str, Any]:
|
||||
"""PATCH /wireguard/config — deep-merge patch into existing config.
|
||||
|
||||
Raises:
|
||||
ValueError: When request body is missing.
|
||||
"""
|
||||
if not body:
|
||||
raise ValueError("Request body required")
|
||||
if "interface" in body:
|
||||
@@ -122,6 +138,7 @@ def patch_config(_request: Any, body: dict[str, Any] | None) -> dict[str, Any]:
|
||||
|
||||
@registry.register("POST", "/wireguard/apply")
|
||||
def apply(_request: Any, _body: Any) -> dict[str, Any]:
|
||||
"""POST /wireguard/apply — render config, write to disk, bring up tunnel via sudo."""
|
||||
cfg = _get_config()
|
||||
conf_text = _generate_conf(cfg)
|
||||
_save_config(cfg)
|
||||
@@ -142,6 +159,7 @@ def apply(_request: Any, _body: Any) -> dict[str, Any]:
|
||||
|
||||
@registry.register("POST", "/wireguard/down")
|
||||
def down(_request: Any, _body: Any) -> dict[str, Any]:
|
||||
"""POST /wireguard/down — bring down the WireGuard tunnel via sudo."""
|
||||
cfg = _get_config()
|
||||
name = cfg["interface"]["name"]
|
||||
run([WG_QUICK_BIN, "down", name], sudo=True)
|
||||
@@ -152,6 +170,7 @@ def down(_request: Any, _body: Any) -> dict[str, Any]:
|
||||
|
||||
@registry.register("GET", "/wireguard/status")
|
||||
def status(_request: Any, _body: Any) -> dict[str, Any]:
|
||||
"""GET /wireguard/status — return current WireGuard status from cache."""
|
||||
wg = _get_wg_state()
|
||||
if wg:
|
||||
return wg.get("status", {"up": False, "interface": {}, "peers": []})
|
||||
@@ -160,6 +179,7 @@ def status(_request: Any, _body: Any) -> dict[str, Any]:
|
||||
|
||||
@registry.register("POST", "/wireguard/initialize")
|
||||
def initialize(_request: Any, _body: Any) -> dict[str, Any]:
|
||||
"""POST /wireguard/initialize — generate keypair and store in config (idempotent)."""
|
||||
cfg = _get_config()
|
||||
if cfg["interface"].get("private_key"):
|
||||
return {"initialized": False, "reason": "already initialized"}
|
||||
@@ -180,6 +200,11 @@ def initialize(_request: Any, _body: Any) -> dict[str, Any]:
|
||||
|
||||
@registry.register("POST", "/wireguard/peers/add")
|
||||
def add_peer(_request: Any, body: dict[str, Any] | None) -> dict[str, Any]:
|
||||
"""POST /wireguard/peers/add — add new peer or update existing one.
|
||||
|
||||
Raises:
|
||||
ValueError: When body is missing or name is empty.
|
||||
"""
|
||||
if not body:
|
||||
raise ValueError("Request body required")
|
||||
name = body.get("name", "").strip()
|
||||
@@ -219,6 +244,12 @@ def add_peer(_request: Any, body: dict[str, Any] | None) -> dict[str, Any]:
|
||||
|
||||
@registry.register("DELETE", "/wireguard/peers/remove")
|
||||
def remove_peer(_request: Any, body: dict[str, Any] | None) -> dict[str, Any]:
|
||||
"""DELETE /wireguard/peers/remove — remove a peer by name.
|
||||
|
||||
Raises:
|
||||
ValueError: When body is missing or name is empty.
|
||||
NotFoundError: When peer does not exist.
|
||||
"""
|
||||
if not body:
|
||||
raise ValueError("Request body required")
|
||||
name = body.get("name", "").strip()
|
||||
@@ -237,6 +268,7 @@ def remove_peer(_request: Any, body: dict[str, Any] | None) -> dict[str, Any]:
|
||||
|
||||
@registry.register("GET", "/wireguard/peers")
|
||||
def list_peers(_request: Any, _body: Any) -> list[dict[str, Any]]:
|
||||
"""GET /wireguard/peers — return configured peers with private keys stripped."""
|
||||
wg = _get_wg_state()
|
||||
if wg:
|
||||
return wg.get("peers", [])
|
||||
@@ -252,6 +284,7 @@ def list_peers(_request: Any, _body: Any) -> list[dict[str, Any]]:
|
||||
|
||||
@registry.register("GET", "/wireguard/peer-status")
|
||||
def get_peer_status(_request: Any, _body: Any) -> list[dict[str, Any]]:
|
||||
"""GET /wireguard/peer-status — return runtime peer status from cache."""
|
||||
wg = _get_wg_state()
|
||||
if wg:
|
||||
return wg.get("status", {}).get("peers", [])
|
||||
@@ -260,6 +293,12 @@ def get_peer_status(_request: Any, _body: Any) -> list[dict[str, Any]]:
|
||||
|
||||
@registry.register("POST", "/wireguard/generate-client")
|
||||
def generate_client_conf(_request: Any, body: dict[str, Any] | None) -> dict[str, Any]:
|
||||
"""POST /wireguard/generate-client — render client-side WireGuard config for a peer.
|
||||
|
||||
Raises:
|
||||
ValueError: When body, name, or server_endpoint is missing.
|
||||
NotFoundError: When peer does not exist or has no private key.
|
||||
"""
|
||||
if not body:
|
||||
raise ValueError("Request body required")
|
||||
name = body.get("name", "").strip()
|
||||
|
||||
Reference in New Issue
Block a user