mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-09 20:26:33 +00:00
Root cause of the DinD DNS-check failure on test-deploy-server
(networks.internet.ip4 falling through to 127.0.0.1 despite
INFINITO_IP4=172.30.0.10 reaching every link of the env pipeline):
cli/administration/inventory/provision/cli.py declared --ip4 with a
hardcoded default of "127.0.0.1" and ensure_host_vars_file wrote that
value unconditionally into host_vars/<host>.yml. group_vars'
defaults_networks.internet.ip4 resolves "172.30.0.10" via
\`lookup('env', 'INFINITO_IP4')\`, but tasks/stages/01_constructor.yml
merges \`defaults_networks | combine(networks | default({}, true))\` so
host_vars wins. INFINITO_IP4 looked broken end-to-end; the breakage
actually lived in the provision-CLI host_vars overlay.
INFINITO_DNS_IP and INFINITO_DOMAIN propagated correctly because
the provision CLI had no --dns and the --primary-domain write was
None-gated and never invoked.
While here, --ssl-disabled and --primary-domain are removed too:
neither had any effect in the dev flow. provision/cli.py applies
\`--vars-file inventories/development/default.yml\` AFTER
ensure_host_vars_file via apply_vars_overrides_from_file, whose
_deep_update_commented_map unconditionally overwrites
(\`target[key] = value\`). The dev vars-file always set
\`TLS_ENABLED: true\`, so \`--ssl-disabled\` (which forced
\`TLS_ENABLED: false\` in host_vars) was systematically reverted to
true. Dev/CI ran with TLS enabled the whole time. Inventory stays at
\`TLS_ENABLED: true\` to preserve that effective behaviour.
Removed from cli/administration/inventory/provision/cli.py:
- --ip4, --ip6: defaulted to 127.0.0.1 / ::1, shadowed group_vars
- --primary-domain: never set by any caller, None-gated write
- --ssl-disabled: always re-overwritten by --vars-file later in the
same provision pass
Removed from cli/administration/inventory/provision/host_vars.py the
matching writes in ensure_host_vars_file; the function now only sets
\`ansible_connection: local\` for localhost-class hosts. Defaults for
DOMAIN_PRIMARY / TLS_ENABLED / networks.internet.{ip4,ip6} live in
group_vars (env-driven) and the inventory vars-file (deployment-wide
flags); host_vars stops duplicating them.
Callers cleaned up:
- cli/administration/deploy/development/inventory/builder.py
- cli/administration/deploy/container/command.py
- scripts/tests/deploy/local/utils/fresh-kept-all-init-and-deploy.sh
- scripts/tests/deploy/local/reset/inventory.sh
Tests + docs follow:
- tests/unit/cli/administration/inventory/provision/test_host_vars.py
now asserts host_vars no longer carries baked DOMAIN_PRIMARY /
TLS_ENABLED / networks defaults
- docs/administration/deploy.md drops --ssl-disabled from the
provision example
- docs/contributing/design/inventory.md re-scopes the host_vars
column: the DOMAIN_PRIMARY / TLS_ENABLED / networks.internet.{ip4,ip6}
values arrive via --vars / --vars-file overlays, otherwise group_vars
provides the env-driven default
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
139 lines
4.4 KiB
Python
139 lines
4.4 KiB
Python
"""Inventory folder materialisation.
|
|
|
|
`build_dev_inventory` is the SPOT that turns a `DevInventorySpec` into a
|
|
fully baked inventory folder via the `infinito administration inventory
|
|
provision` CLI. `build_dev_inventory_matrix` is the orchestrator: it
|
|
runs the planner and builds every round's folder.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
from typing import TYPE_CHECKING, Any
|
|
|
|
from cli.administration.deploy.development.common import DEV_INVENTORY_VARS_FILE
|
|
from cli.administration.deploy.development.mirrors import (
|
|
generate_ci_mirrors_file,
|
|
should_use_mirrors_on_ci,
|
|
)
|
|
|
|
from .payload import _bake_overrides, _resolve_variant_payloads
|
|
from .planner import plan_dev_inventory_matrix
|
|
from .spec import DevInventorySpec, PlanEntry
|
|
|
|
if TYPE_CHECKING:
|
|
from collections.abc import Mapping, Sequence
|
|
|
|
from cli.administration.deploy.development.compose import Compose
|
|
|
|
|
|
def build_dev_inventory(compose: Compose, spec: DevInventorySpec) -> None:
|
|
"""Build the inventory folder described by `spec` and ensure its
|
|
vault password file exists. Two side-effects, no return value: after
|
|
this call, `spec.inventory_dir` contains a complete, variant-resolved
|
|
inventory.
|
|
"""
|
|
inv_root = spec.inventory_root()
|
|
|
|
variant_payloads = _resolve_variant_payloads(
|
|
roles_dir=str(compose.repo_root / "roles"),
|
|
include=spec.include,
|
|
active_variants=spec.variant_selectors(),
|
|
)
|
|
vars_payload = _bake_overrides(
|
|
base_overrides=spec.overrides(),
|
|
variant_payloads=variant_payloads,
|
|
)
|
|
|
|
cmd = [
|
|
"infinito",
|
|
"administration",
|
|
"inventory",
|
|
"provision",
|
|
inv_root,
|
|
"--host",
|
|
"localhost",
|
|
"--vars-file",
|
|
DEV_INVENTORY_VARS_FILE,
|
|
"--vars",
|
|
json.dumps(vars_payload, sort_keys=True),
|
|
"--include",
|
|
",".join(spec.include),
|
|
]
|
|
|
|
if should_use_mirrors_on_ci():
|
|
mirrors_file = generate_ci_mirrors_file(compose, inventory_dir=inv_root)
|
|
cmd += ["--mirror", mirrors_file]
|
|
|
|
extra_env: dict[str, str] = {}
|
|
if spec.services_disabled:
|
|
extra_env["INFINITO_SERVICES_DISABLED"] = spec.services_disabled
|
|
|
|
compose.exec(
|
|
cmd,
|
|
check=True,
|
|
workdir=os.environ["INFINITO_SRC_DIR"],
|
|
extra_env=extra_env or None,
|
|
)
|
|
_ensure_vault_password_file(compose, inventory_dir=inv_root)
|
|
|
|
|
|
def build_dev_inventory_matrix(
|
|
compose: Compose,
|
|
*,
|
|
base_inventory_dir: str,
|
|
primary_apps: Sequence[str],
|
|
storage_constrained: bool,
|
|
runtime: str,
|
|
extra_vars: Mapping[str, Any] | None = None,
|
|
services_disabled: str = "",
|
|
include_filter: Sequence[str] | None = None,
|
|
) -> list[PlanEntry]:
|
|
"""Build every folder in the matrix plan and return the plan.
|
|
|
|
`include_filter`, when provided, is the set of role names a caller
|
|
has already filtered (e.g. by INFINITO_SERVICES_DISABLED removal of provider
|
|
roles). Each round's include is intersected with this set before
|
|
being baked, so the inventory and `--include` flag stay aligned
|
|
with whatever the deploy step will actually deploy.
|
|
"""
|
|
plan = plan_dev_inventory_matrix(
|
|
roles_dir=str(compose.repo_root / "roles"),
|
|
primary_apps=primary_apps,
|
|
base_inventory_dir=base_inventory_dir,
|
|
)
|
|
allow: set[str] | None = set(include_filter) if include_filter is not None else None
|
|
for _round_index, inv_dir, round_variants, raw_include, _purge_set in plan:
|
|
round_include = (
|
|
tuple(role for role in raw_include if role in allow)
|
|
if allow is not None
|
|
else raw_include
|
|
)
|
|
spec = DevInventorySpec(
|
|
inventory_dir=inv_dir,
|
|
include=round_include,
|
|
storage_constrained=storage_constrained,
|
|
runtime=runtime,
|
|
extra_vars=extra_vars,
|
|
services_disabled=services_disabled,
|
|
active_variants=round_variants,
|
|
)
|
|
build_dev_inventory(compose, spec)
|
|
return plan
|
|
|
|
|
|
def _ensure_vault_password_file(compose: Compose, *, inventory_dir: str) -> None:
|
|
inv_root = str(inventory_dir).rstrip("/")
|
|
pw_file = f"{inv_root}/.password"
|
|
compose.exec(
|
|
[
|
|
"sh",
|
|
"-lc",
|
|
f"mkdir -p {inv_root} && "
|
|
f"[ -f {pw_file} ] || "
|
|
f"printf '%s\n' 'ci-vault-password' > {pw_file}",
|
|
],
|
|
check=True,
|
|
)
|