mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-07 03:15:56 +00:00
Matrix-deploy variant transitions left per-domain vhost files behind:
when a service dropped out of a round's include set, sys-svc-compose's
docker prune removed its container but the vhost under
<NGINX_DIR>/conf.d/servers/{http,https}/<domain>.conf survived, making
the next round's HTTPS probe see 502 instead of TLS-error 000 (5 failed
test-development jobs on run 25705903504).
The inter-round purge in cli.administration.deploy.development.deploy
already invokes scripts/tests/deploy/local/purge/entity.sh with the
previous round's full include — the missing piece was an entity-keyed
nginx primitive next to db/compose/dir. Add it:
- utils.roles.entity_apps.apps_for_entity: reverse of get_entity_name,
walks roles/*/vars/main.yml to map entity -> [application_id]
- utils.cleanup.nginx_vhosts: resolves entity -> apps -> canonical+alias
domains (via build_applications_from_roles + iter_app_domains so it
stays ansible-free) and removes the matching vhost files
- scripts/container/purge/entity/nginx.sh: thin bash wrapper,
symmetric to db/compose/dir
- scripts/container/purge/apps.sh: drive nginx.sh inside the entity
loop, alongside db/compose/dir
Tests: 14 new unit tests covering the reverse-lookup edge cases and
the purge iterator (existing-only / aliases / multi-entity / no-op CLI).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
60 lines
2.0 KiB
Python
60 lines
2.0 KiB
Python
"""Reverse entity -> application_id resolver.
|
|
|
|
`utils.roles.entity_name.get_entity_name` maps a role / application_id to
|
|
its compose entity name (the longest matching category prefix stripped).
|
|
The purge orchestrators need the inverse: given an entity name, which
|
|
application_ids belong to it? This helper walks the roles directory and
|
|
returns that mapping.
|
|
|
|
Used by `utils.cleanup.nginx_vhosts` so an entity-keyed purge can
|
|
enumerate the per-app domains whose nginx vhost files belong to the
|
|
stack being torn down.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING
|
|
|
|
from utils.cache.yaml import load_yaml_any
|
|
from utils.roles.entity_name import get_entity_name
|
|
from utils.roles.mapping import ROLE_FILE_VARS_MAIN
|
|
|
|
if TYPE_CHECKING:
|
|
from pathlib import Path
|
|
|
|
|
|
def _role_app_id(role_dir: Path) -> str:
|
|
"""Return the role's application_id (vars/main.yml.application_id),
|
|
falling back to the directory name when the field is missing or the
|
|
file does not exist. Mirrors `utils.roles.validation.invokable._role_to_app_id`.
|
|
"""
|
|
vars_file = role_dir / ROLE_FILE_VARS_MAIN
|
|
if not vars_file.is_file():
|
|
return role_dir.name
|
|
data = load_yaml_any(str(vars_file), default_if_missing={}) or {}
|
|
if not isinstance(data, dict):
|
|
return role_dir.name
|
|
app_id = data.get("application_id")
|
|
return str(app_id) if app_id else role_dir.name
|
|
|
|
|
|
def apps_for_entity(entity: str, *, roles_dir: Path) -> list[str]:
|
|
"""Return sorted, deduplicated application_ids whose role belongs to
|
|
*entity* under `get_entity_name`.
|
|
|
|
Returns an empty list when *entity* is blank, *roles_dir* is not a
|
|
directory, or no role matches.
|
|
"""
|
|
target = entity.strip()
|
|
if not target or not roles_dir.is_dir():
|
|
return []
|
|
|
|
out: set[str] = set()
|
|
for role_dir in sorted(p for p in roles_dir.iterdir() if p.is_dir()):
|
|
app_id = _role_app_id(role_dir)
|
|
if not app_id:
|
|
continue
|
|
if get_entity_name(app_id) == target:
|
|
out.add(app_id)
|
|
return sorted(out)
|