Files
apex.ermnvldmr.com/scripts/engine/context.py
T

114 lines
4.1 KiB
Python

# scripts/engine/context.py
"""Context and filesystem paths available to actions."""
from __future__ import annotations
import os
from engine.lib.log import Log
from engine.lib.sys import Sys
from engine.lib.tpl import Tpl
from engine.lib.host import Host
from engine.lib.ufw import Ufw
from engine.lib.crowdsec import Crowdsec
from engine.lib.systemd import Systemd
from engine.lib.notify import Notify
class Paths:
def __init__(self, repo_root: str, commons_dir: str):
self.repo_root = repo_root
self.commons = commons_dir
self.proprietaries = os.path.join(repo_root, "proprietaries")
self.configs = os.path.join(repo_root, "configs")
self.compositions = os.path.join(repo_root, "compositions")
self.core = os.path.join(self.compositions, "apex")
def _tier(self, n: int) -> str:
return os.path.realpath(os.path.join(self.core, f"@tier{n}"))
def _stier(self, n: int) -> str:
return os.path.realpath(os.path.join(self.core, f"@tier{n}", "shared"))
def _root_tier(self, n: int) -> str:
return os.path.realpath(os.path.join(self.compositions, f"@tier{n}"))
@property
def root_tier1(self): return self._root_tier(1)
@property
def root_tier2(self): return self._root_tier(2)
@property
def root_tier3(self): return self._root_tier(3)
@property
def tier1(self): return self._tier(1)
@property
def tier2(self): return self._tier(2)
@property
def tier3(self): return self._tier(3)
@property
def stier1(self): return self._stier(1)
@property
def stier2(self): return self._stier(2)
@property
def stier3(self): return self._stier(3)
class _CommonsWrap:
"""ctx.commons — lazily loads and runs the shadowed commons action (opt-in wrap)."""
def __init__(self, ctx, shadowed_path):
self._ctx = ctx
self._path = shadowed_path
self._mod = None
def run(self, args):
if not self._path:
raise RuntimeError("ctx.commons is only available when a commons action is shadowed")
from engine import overlay
if self._mod is None:
self._mod = overlay.load_module(self._path, "apex_commons_shadowed")
return self._mod.run(self._ctx, args)
class Context:
def __init__(self, node, paths: Paths, action_name: str, shadowed=None):
self.node = node
self.paths = paths
self.action = action_name
name = node.name if node else "global"
self.log = Log(name, action_name)
self.sys = Sys(self.log)
self.tpl = Tpl(paths.configs, self.log)
self.host = Host(self.log, self.sys)
self.ufw = Ufw(self.log, self.sys, self.host)
self.crowdsec = Crowdsec(self.log, self.sys, self.tpl, self.host)
self.systemd = Systemd(self.log, self.sys, self.tpl, self.host)
self.notify = Notify(self.log, node.host if node else "global")
self._shadowed = shadowed
self._commons = None
@property
def commons(self) -> _CommonsWrap:
if self._commons is None:
self._commons = _CommonsWrap(self, self._shadowed)
return self._commons
def vars(self) -> dict:
"""Substitution variable set for templating: os.environ + apex identity/paths."""
v = dict(os.environ)
v["APEX_COMMONS"] = self.paths.commons # absolute launcher dir (for crontab/systemd)
v["APEX_REPO_ROOT"] = self.paths.repo_root
if self.node:
v.update({
"APEX_NODE_HOST": self.node.host,
"APEX_NODE_FQDN": self.node.fqdn,
"APEX_SUBNET": self.node.subnet,
"APEX_TIER1": self.paths.tier1, "APEX_TIER2": self.paths.tier2,
"APEX_TIER3": self.paths.tier3,
"APEX_TIER1_SHARED": self.paths.stier1,
"APEX_TIER2_SHARED": self.paths.stier2,
"APEX_TIER3_SHARED": self.paths.stier3,
"APEX_TIER_ROOT1": self.paths.root_tier1,
"APEX_TIER_ROOT2": self.paths.root_tier2,
"APEX_TIER_ROOT3": self.paths.root_tier3,
})
return v