80 lines
1.9 KiB
Python
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)
|