fester/backend/nodes/roles_store.py

80 lines
1.9 KiB
Python

import json
import os
from pathlib import Path
from backend.nodes.roles import NodeRole
# Where node role overrides are persisted. Allow override via env var;
# otherwise default to a user-writable path under /var/lib/fester (or
# fall back to a tmp dir if neither is writable).
def _resolve_role_db() -> Path:
env = os.environ.get("FESTER_ROLE_DB")
if env:
return Path(env)
candidates = [
Path("/etc/fester/node_roles.json"),
Path("/var/lib/fester/node_roles.json"),
Path.home() / ".fester" / "node_roles.json",
Path("/tmp/fester_node_roles.json"),
]
for c in candidates:
try:
c.parent.mkdir(parents=True, exist_ok=True)
# touch to verify writability
if not c.exists():
c.write_text("{}")
else:
# verify we can write to it
with open(c, "a"):
pass
return c
except (OSError, PermissionError):
continue
# Last resort: in-memory only (caller must handle None)
return None
ROLE_DB = _resolve_role_db()
DEFAULT_ROLE = NodeRole(name="default")
def load_roles():
if ROLE_DB is None or not ROLE_DB.exists():
return {}
try:
raw = json.loads(ROLE_DB.read_text())
except Exception:
return {}
roles = {}
for node, cfg in raw.items():
try:
roles[node] = NodeRole(**cfg)
except TypeError:
# Schema drift — skip malformed entries
continue
return roles
def save_roles(roles):
if ROLE_DB is None:
return False
raw = {
node: role.__dict__
for node, role in roles.items()
}
try:
ROLE_DB.write_text(json.dumps(raw, indent=2))
return True
except (OSError, PermissionError):
return False
def get_role(node_name, roles):
return roles.get(node_name, DEFAULT_ROLE)