mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-10 04:36:40 +00:00
138 lines
3.8 KiB
Python
138 lines
3.8 KiB
Python
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
import yaml
|
|
|
|
PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
|
ROLES_DIR = PROJECT_ROOT / "roles"
|
|
|
|
|
|
def _render_ansible_strict(
|
|
*, raw: str, var_name: str, variables: dict[str, Any]
|
|
) -> str:
|
|
from utils.templating import render_ansible_strict
|
|
|
|
return render_ansible_strict(
|
|
templar=None,
|
|
raw=raw,
|
|
var_name=var_name,
|
|
err_prefix="domains.list",
|
|
variables=variables,
|
|
)
|
|
|
|
|
|
def _build_domain_index(
|
|
applications: dict[str, Any], include_aliases: bool = True
|
|
) -> dict[str, str]:
|
|
from utils.domains.application_domain_index import build_domain_index
|
|
|
|
return build_domain_index(applications, include_aliases=include_aliases)
|
|
|
|
|
|
def load_yaml_mapping(path: Path) -> dict[str, Any]:
|
|
if not path.exists():
|
|
return {}
|
|
|
|
data = yaml.safe_load(path.read_text(encoding="utf-8")) or {}
|
|
if not isinstance(data, dict):
|
|
raise ValueError(f"{path} must contain a YAML mapping")
|
|
return data
|
|
|
|
|
|
def render_domain_value(value: Any, variables: dict[str, Any], field_name: str) -> Any:
|
|
if isinstance(value, str):
|
|
return _render_ansible_strict(
|
|
raw=value,
|
|
var_name=field_name,
|
|
variables=variables,
|
|
)
|
|
|
|
if isinstance(value, list):
|
|
return [
|
|
render_domain_value(item, variables, f"{field_name}[{idx}]")
|
|
for idx, item in enumerate(value)
|
|
]
|
|
|
|
if isinstance(value, dict):
|
|
return {
|
|
key: render_domain_value(item, variables, f"{field_name}.{key}")
|
|
for key, item in value.items()
|
|
}
|
|
|
|
return value
|
|
|
|
|
|
def build_applications_from_roles(
|
|
roles_dir: Path, domain_primary: str
|
|
) -> dict[str, dict[str, Any]]:
|
|
variables = {"DOMAIN_PRIMARY": domain_primary}
|
|
applications: dict[str, dict[str, Any]] = {}
|
|
|
|
for role_dir in sorted(roles_dir.iterdir()):
|
|
vars_main = role_dir / "vars" / "main.yml"
|
|
config_main = role_dir / "config" / "main.yml"
|
|
if not vars_main.exists() or not config_main.exists():
|
|
continue
|
|
|
|
vars_data = load_yaml_mapping(vars_main)
|
|
application_id = vars_data.get("application_id")
|
|
if not isinstance(application_id, str) or not application_id.strip():
|
|
continue
|
|
|
|
config_data = load_yaml_mapping(config_main)
|
|
server = config_data.get("server")
|
|
if not isinstance(server, dict):
|
|
continue
|
|
|
|
domains = server.get("domains")
|
|
if not isinstance(domains, dict):
|
|
continue
|
|
|
|
applications[application_id] = {
|
|
"server": {
|
|
"domains": render_domain_value(
|
|
domains,
|
|
variables,
|
|
f"{application_id}.server.domains",
|
|
)
|
|
}
|
|
}
|
|
|
|
return applications
|
|
|
|
|
|
def list_derived_domains(domain_primary: str) -> list[str]:
|
|
primary = str(domain_primary).strip().lower()
|
|
if not primary:
|
|
return []
|
|
|
|
# Keep non-role domains that are part of the stack contract in one place.
|
|
return [f"test.{primary}"]
|
|
|
|
|
|
def add_www_variants(domains: list[str]) -> list[str]:
|
|
expanded = set(domains)
|
|
for domain in list(expanded):
|
|
if not domain.startswith("www."):
|
|
expanded.add(f"www.{domain}")
|
|
return sorted(expanded)
|
|
|
|
|
|
def list_application_domains(
|
|
domain_primary: str,
|
|
*,
|
|
include_aliases: bool = False,
|
|
include_www: bool = False,
|
|
) -> list[str]:
|
|
applications = build_applications_from_roles(ROLES_DIR, domain_primary)
|
|
domains = set(
|
|
_build_domain_index(applications, include_aliases=include_aliases).keys()
|
|
)
|
|
domains.update(list_derived_domains(domain_primary))
|
|
sorted_domains = sorted(domains)
|
|
if include_www:
|
|
return add_www_variants(sorted_domains)
|
|
return sorted_domains
|