Files
computer-playbook/cli/administration/inventory/provision/role_resolver.py
kevinveenbirkenbachandClaude Opus 5 6e2b36c3d0 fix(inventory): resolve a system service id to no role
The applications: host_vars block is the config namespace keyed by role id, so it also carries system services (sys-ctl-hlth-csp, sys-svc-container). Those declare system_service_id and match no application role, and the resolver died on them instead of reporting their absence.

role_name now raises RoleNotFoundError and exits 3, distinct from argparse's usage error (2) and from a genuine failure (1). run_subprocess grew ok_returncodes so a caller can accept an expected non-zero status while every other failure still surfaces, and resolve_role_path returns None for that code.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-15 13:42:32 +02:00

65 lines
1.5 KiB
Python

from __future__ import annotations
import sys
from pathlib import Path
from cli.meta.roles.applications.role_name import EXIT_NO_SUCH_APPLICATION_ROLE
from .subprocess_runner import run_subprocess
def resolve_role_path(
application_id: str,
roles_dir: Path,
project_root: Path,
env: dict[str, str] | None,
) -> Path | None:
"""
Resolve role path by calling:
python -m cli.meta.roles.applications.role_name <app_id> -r <roles_dir>
The helper may print:
- bare folder name (e.g. web-app-nextcloud)
- relative path (e.g. roles/web-app-nextcloud)
- absolute path
Returns None when the id belongs to no application role.
"""
cmd = [
sys.executable,
"-m",
"cli.meta.roles.applications.role_name",
application_id,
"-r",
str(roles_dir),
]
result = run_subprocess(
cmd,
capture_output=True,
env=env,
ok_returncodes=(0, EXIT_NO_SUCH_APPLICATION_ROLE),
)
if result.returncode == EXIT_NO_SUCH_APPLICATION_ROLE:
return None
raw = (result.stdout or "").strip()
if not raw:
return None
printed = Path(raw)
if printed.is_absolute():
role_path = printed
else:
cand1 = roles_dir / printed
if cand1.exists():
role_path = cand1
else:
cand2 = project_root / printed
if cand2.exists():
role_path = cand2
else:
return None
return role_path if role_path.exists() else None