feat: implement plugin manager service bootstrap and add tests

This commit is contained in:
Rightup committed 2026-09-07 10:31:05 +01:00
1 parent b65e54196b
commit 3afec59c1a
3 files changed
+148

No files matched your search

+11
View File
@@ -291,6 +291,17 @@ class RepeaterDaemon:
logger.info(f"Initializing repeater: {self.config['repeater']['node_name']}")
try:
from repeater.service_utils import ensure_plugin_manager_service
ok, msg = ensure_plugin_manager_service()
if ok:
logger.info("Plugin-manager bootstrap: %s", msg)
else:
logger.warning("Plugin-manager bootstrap: %s", msg)
except Exception as exc: # pragma: no cover - defensive safeguard
logger.warning("Plugin-manager bootstrap check raised an exception: %s", exc)
# -----------------------------------------------
# Get the actual Network IP Address
try:
+117
View File
@@ -96,6 +96,123 @@ def get_container_restart_message() -> str:
)
def ensure_plugin_manager_service() -> Tuple[bool, str]:
"""Ensure the packaged plugin-manager systemd unit is installed and running.
This is intentionally idempotent and root-only. It is safe to run during
startup and after upgrades so a single upgrade can heal older installs that
pre-date the plugin-manager system service.
"""
if is_container() or is_buildroot():
return True, "Plugin-manager bootstrap skipped in container/buildroot environment"
if os.geteuid() != 0:
logger.info(
"Plugin-manager bootstrap skipped: root privileges required for systemd provisioning"
)
return (
True,
"Plugin-manager bootstrap skipped: root privileges required for systemd provisioning",
)
venv_python = "/opt/openhop_repeater/venv/bin/python"
if not os.path.isfile(venv_python):
return False, "Plugin-manager bootstrap skipped: venv not present"
package_unit = None
code = """
from importlib.metadata import distribution
from pathlib import Path
import sys
try:
dist = distribution('openhop_repeater')
except Exception:
sys.exit(1)
try:
path = Path(dist.locate_file('repeater/plugins/openhop-plugin-manager.service'))
except Exception:
sys.exit(1)
if path.is_file():
print(path)
sys.exit(0)
sys.exit(1)
"""
try:
result = subprocess.run(
[venv_python, "-I", "-c", code],
capture_output=True,
text=True,
timeout=20,
check=False,
)
if result.returncode == 0 and result.stdout.strip():
package_unit = result.stdout.strip().splitlines()[-1]
except (OSError, subprocess.TimeoutExpired) as exc:
logger.warning("Plugin-manager bootstrap lookup failed: %s", exc)
return False, f"Plugin-manager bootstrap lookup failed: {exc}"
if not package_unit:
return (
False,
"Plugin-manager bootstrap skipped: packaged service not found in installed package",
)
unit_path = "/etc/systemd/system/openhop-plugin-manager.service"
changed = False
try:
if not os.path.exists(unit_path):
logger.info("Plugin-manager unit missing; installing packaged service")
changed = True
else:
with open(package_unit, "rb") as src, open(unit_path, "rb") as dst:
if src.read() != dst.read():
logger.info("Plugin-manager unit differs from packaged version; updating")
changed = True
if changed:
shutil.copy2(package_unit, unit_path)
subprocess.run(
[_SYSTEMCTL_BIN, "daemon-reload"], check=False, capture_output=True, text=True
)
logger.info("Plugin-manager unit installed or refreshed")
else:
logger.info("Plugin-manager unit already matches packaged version")
subprocess.run(
[_SYSTEMCTL_BIN, "enable", "openhop-plugin-manager"],
check=False,
capture_output=True,
text=True,
)
active = subprocess.run(
[_SYSTEMCTL_BIN, "is-active", "--quiet", "openhop-plugin-manager"],
check=False,
capture_output=True,
text=True,
)
if active.returncode != 0:
logger.info("Starting plugin-manager service")
subprocess.run(
[_SYSTEMCTL_BIN, "start", "openhop-plugin-manager"],
check=False,
capture_output=True,
text=True,
)
elif changed:
logger.info("Restarting plugin-manager service after unit refresh")
subprocess.run(
[_SYSTEMCTL_BIN, "restart", "openhop-plugin-manager"],
check=False,
capture_output=True,
text=True,
)
return True, "Plugin-manager service is installed and active"
except Exception as exc:
logger.warning("Plugin-manager bootstrap failed: %s", exc)
return False, f"Plugin-manager bootstrap failed: {exc}"
def restart_service() -> Tuple[bool, str]:
"""
Restart the openhop-repeater service.