mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 10:59:59 +00:00
compose_networks, container_networks and compose_external_networks each rebuilt the same Ansible-side context before calling their renderer: resolve the variables, settle the deployment mode, load applications, build the service registry, and close over the config and database lookups. Around forty lines, three times, each with its own copy of _resolve_var. A change to how the registry or the closures are obtained could reach one lookup and miss another. build_context() returns that context once. honour_mode_force carries the only real difference between the callers: compose_external_networks never consulted compose_mode_force, and still does not. The lookups keep only what is theirs - term validation, their own arguments, their renderer call - and drop from 94/90/87 lines to 59/54/53. No assertion changed in the tests; only the mock targets moved with the seam, from the plugin modules to utils.networks.lookup_context. Twelve legacy comments in those test files lost their grandfathering when the files entered the lint's diff scope: two became docstrings naming the call contract, the rest were narration and are gone. Behaviour-preserving: the same 13 lookup tests pass before and after. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
99 lines
3.2 KiB
Python
99 lines
3.2 KiB
Python
"""Shared Ansible-side assembly for the network lookup plugins.
|
|
|
|
Every one of them needs the same four things before it can call into
|
|
:mod:`utils.networks.render`: the resolved variables, the deployment mode, a
|
|
service registry built from the merged applications, and closures over the
|
|
``config`` and ``database`` lookups. Building that once means a change to how
|
|
the registry or the closures are obtained cannot reach one lookup and miss
|
|
another.
|
|
|
|
Args of :func:`build_context` are documented on the function.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import contextlib
|
|
from dataclasses import dataclass
|
|
from typing import TYPE_CHECKING, Any
|
|
|
|
from ansible.plugins.loader import lookup_loader
|
|
|
|
from utils.roles.applications.services.registry import (
|
|
build_service_registry_from_applications,
|
|
)
|
|
|
|
if TYPE_CHECKING:
|
|
from collections.abc import Callable
|
|
|
|
|
|
def resolve_var(templar: Any, value: Any) -> Any:
|
|
"""Template ``value`` when a templar is available, else pass it through.
|
|
|
|
Args:
|
|
templar: the plugin's templar, or None.
|
|
value: raw variable value.
|
|
"""
|
|
if templar is None:
|
|
return value
|
|
with contextlib.suppress(Exception):
|
|
return templar.template(value)
|
|
return value
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class NetworkLookupContext:
|
|
"""What a network lookup needs to call the renderers."""
|
|
|
|
vars: dict[str, Any]
|
|
templar: Any
|
|
deployment_mode: str
|
|
registry: dict[str, dict[str, Any]]
|
|
lookup_config: Callable[[str, str, Any], Any]
|
|
lookup_database: Callable[[str, str], Any]
|
|
|
|
|
|
def build_context(
|
|
lookup: Any,
|
|
variables: dict[str, Any] | None,
|
|
*,
|
|
honour_mode_force: bool = True,
|
|
) -> NetworkLookupContext:
|
|
"""Assemble the shared context for a network lookup.
|
|
|
|
Args:
|
|
lookup: the LookupModule instance, for its templar and loader.
|
|
variables: the variables Ansible passed to ``run``.
|
|
honour_mode_force: let ``compose_mode_force`` override DEPLOYMENT_MODE.
|
|
"""
|
|
templar = getattr(lookup, "_templar", None)
|
|
vars_ = variables or getattr(templar, "available_variables", {}) or {}
|
|
|
|
deployment_mode = str(resolve_var(templar, vars_.get("DEPLOYMENT_MODE", "compose")))
|
|
if honour_mode_force:
|
|
mode_force = resolve_var(templar, vars_.get("compose_mode_force", ""))
|
|
deployment_mode = str(mode_force or deployment_mode).strip()
|
|
|
|
applications = lookup_loader.get(
|
|
"applications", loader=lookup._loader, templar=templar
|
|
).run([], variables=vars_)[0]
|
|
|
|
config_lookup = lookup_loader.get("config", loader=lookup._loader, templar=templar)
|
|
database_lookup = lookup_loader.get(
|
|
"database", loader=lookup._loader, templar=templar
|
|
)
|
|
|
|
def _lookup_config(app: str, path: str, default: Any) -> Any:
|
|
return config_lookup.run([app, path, default], variables=vars_)[0]
|
|
|
|
def _lookup_database(app: str, key: str) -> Any:
|
|
return database_lookup.run([app, key], variables=vars_)[0]
|
|
|
|
return NetworkLookupContext(
|
|
vars=vars_,
|
|
templar=templar,
|
|
deployment_mode=deployment_mode,
|
|
registry=build_service_registry_from_applications(applications),
|
|
lookup_config=_lookup_config,
|
|
lookup_database=_lookup_database,
|
|
)
|