123 lines
4.4 KiB
Python
123 lines
4.4 KiB
Python
from __future__ import annotations
|
|
|
|
import importlib.util
|
|
from pathlib import Path
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
SCRIPT_PATH = ROOT / "scripts" / "fleet_config_sync.py"
|
|
HOSTS_FILE = ROOT / "ansible" / "inventory" / "hosts.ini"
|
|
EXAMPLE_MANIFEST = ROOT / "docs" / "fleet-config-sync.example.yaml"
|
|
|
|
|
|
def _load_module(path: Path, name: str):
|
|
assert path.exists(), f"missing {path.relative_to(ROOT)}"
|
|
spec = importlib.util.spec_from_file_location(name, path)
|
|
assert spec and spec.loader
|
|
module = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(module)
|
|
return module
|
|
|
|
|
|
def _write_source_tree(tmp_path: Path) -> Path:
|
|
source_root = tmp_path / "source"
|
|
(source_root / "dispatch").mkdir(parents=True)
|
|
(source_root / "config.yaml").write_text("model: local\nroute: hybrid\n", encoding="utf-8")
|
|
(source_root / "dispatch" / "rules.json").write_text('{"lane":"allegro"}\n', encoding="utf-8")
|
|
return source_root
|
|
|
|
|
|
def test_example_manifest_targets_known_fleet_hosts() -> None:
|
|
mod = _load_module(SCRIPT_PATH, "fleet_config_sync")
|
|
assert EXAMPLE_MANIFEST.exists(), "missing docs/fleet-config-sync.example.yaml"
|
|
|
|
inventory = mod.load_inventory_hosts(HOSTS_FILE)
|
|
manifest = mod.load_manifest(EXAMPLE_MANIFEST)
|
|
mod.validate_manifest(manifest, inventory)
|
|
|
|
assert [target["host"] for target in manifest["targets"]] == ["ezra", "bezalel"]
|
|
|
|
|
|
def test_build_rollout_plan_stages_one_release_for_all_hosts(tmp_path: Path) -> None:
|
|
mod = _load_module(SCRIPT_PATH, "fleet_config_sync")
|
|
source_root = _write_source_tree(tmp_path)
|
|
inventory = {
|
|
"ezra": {"host": "ezra", "ansible_host": "143.198.27.163"},
|
|
"bezalel": {"host": "bezalel", "ansible_host": "67.205.155.108"},
|
|
}
|
|
manifest = {
|
|
"fleet_name": "phase-3-config-sync",
|
|
"targets": [
|
|
{
|
|
"host": "ezra",
|
|
"config_root": "/root/wizards/ezra/home/.hermes",
|
|
"files": ["config.yaml", "dispatch/rules.json"],
|
|
},
|
|
{
|
|
"host": "bezalel",
|
|
"config_root": "/root/wizards/bezalel/home/.hermes",
|
|
"files": ["config.yaml", "dispatch/rules.json"],
|
|
},
|
|
],
|
|
}
|
|
|
|
plan = mod.build_rollout_plan(manifest, inventory, source_root=source_root)
|
|
|
|
assert plan["fleet_name"] == "phase-3-config-sync"
|
|
assert len(plan["release_id"]) == 12
|
|
assert plan["target_count"] == 2
|
|
assert plan["file_count"] == 4
|
|
assert plan["total_bytes"] > 0
|
|
|
|
for target in plan["targets"]:
|
|
assert target["stage_root"].endswith(f"/.releases/{plan['release_id']}")
|
|
assert target["live_symlink"].endswith("/current")
|
|
assert target["promote"]["release_id"] == plan["release_id"]
|
|
assert {item["relative_path"] for item in target["files"]} == {"config.yaml", "dispatch/rules.json"}
|
|
|
|
|
|
def test_validate_manifest_rejects_unknown_inventory_host(tmp_path: Path) -> None:
|
|
mod = _load_module(SCRIPT_PATH, "fleet_config_sync")
|
|
source_root = _write_source_tree(tmp_path)
|
|
manifest = {
|
|
"targets": [
|
|
{
|
|
"host": "unknown-wizard",
|
|
"config_root": "/srv/wizard/config",
|
|
"files": ["config.yaml"],
|
|
}
|
|
]
|
|
}
|
|
|
|
try:
|
|
mod.build_rollout_plan(manifest, {"ezra": {"host": "ezra"}}, source_root=source_root)
|
|
except ValueError as exc:
|
|
assert "unknown inventory host" in str(exc)
|
|
assert "unknown-wizard" in str(exc)
|
|
else:
|
|
raise AssertionError("build_rollout_plan should reject unknown inventory hosts")
|
|
|
|
|
|
def test_render_markdown_mentions_atomic_promote_and_targets(tmp_path: Path) -> None:
|
|
mod = _load_module(SCRIPT_PATH, "fleet_config_sync")
|
|
source_root = _write_source_tree(tmp_path)
|
|
manifest = {
|
|
"fleet_name": "phase-3-config-sync",
|
|
"targets": [
|
|
{
|
|
"host": "ezra",
|
|
"config_root": "/root/wizards/ezra/home/.hermes",
|
|
"files": ["config.yaml"],
|
|
}
|
|
],
|
|
}
|
|
inventory = {"ezra": {"host": "ezra", "ansible_host": "143.198.27.163"}}
|
|
|
|
plan = mod.build_rollout_plan(manifest, inventory, source_root=source_root)
|
|
report = mod.render_markdown(plan)
|
|
|
|
assert plan["release_id"] in report
|
|
assert "Atomic promote via symlink swap" in report
|
|
assert "ezra" in report
|
|
assert "/root/wizards/ezra/home/.hermes/current" in report
|