fix(topology): anchor compose path to run dir, stop install-dir litter
_topology_compose_path returned a CWD-relative Path, so every deploy/mutate/dry-run wrote decnet-topology-<id8>-compose.yml into the process CWD (the install dir). Teardown computed the same relative path against its own CWD, so when it differed the unlink() missed the orphan and files accumulated forever. Anchor to $DECNET_RUN_DIR (default /var/lib/decnet/topologies, tempdir fallback) so write and teardown always agree regardless of CWD.
This commit is contained in:
@@ -5,8 +5,10 @@ Deploy, teardown, and status via Docker SDK + subprocess docker compose.
|
|||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess # nosec B404
|
import subprocess # nosec B404
|
||||||
|
import tempfile
|
||||||
import time
|
import time
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import cast
|
from typing import cast
|
||||||
@@ -833,7 +835,16 @@ def _teardown_order(lans: list[dict]) -> list[str]:
|
|||||||
|
|
||||||
|
|
||||||
def _topology_compose_path(topology_id: str) -> Path:
|
def _topology_compose_path(topology_id: str) -> Path:
|
||||||
return Path(f"decnet-topology-{topology_id[:8]}-compose.yml")
|
# Anchor to a stable absolute dir so write and teardown agree
|
||||||
|
# regardless of process CWD — a CWD-relative path littered the
|
||||||
|
# install tree and let teardown's unlink() miss orphaned files.
|
||||||
|
base = Path(os.environ.get("DECNET_RUN_DIR", "/var/lib/decnet/topologies"))
|
||||||
|
try:
|
||||||
|
base.mkdir(parents=True, exist_ok=True)
|
||||||
|
except OSError:
|
||||||
|
base = Path(tempfile.gettempdir()) / "decnet-topologies"
|
||||||
|
base.mkdir(parents=True, exist_ok=True)
|
||||||
|
return base / f"decnet-topology-{topology_id[:8]}-compose.yml"
|
||||||
|
|
||||||
|
|
||||||
def _topology_compose_project(topology_id: str) -> str:
|
def _topology_compose_project(topology_id: str) -> str:
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ async def repo(tmp_path):
|
|||||||
|
|
||||||
@pytest.mark.anyio
|
@pytest.mark.anyio
|
||||||
async def test_dry_run_writes_compose_and_preserves_pending(repo, tmp_path, monkeypatch):
|
async def test_dry_run_writes_compose_and_preserves_pending(repo, tmp_path, monkeypatch):
|
||||||
monkeypatch.chdir(tmp_path)
|
monkeypatch.setenv("DECNET_RUN_DIR", str(tmp_path))
|
||||||
plan = generate(_cfg())
|
plan = generate(_cfg())
|
||||||
tid = await persist(repo, plan)
|
tid = await persist(repo, plan)
|
||||||
|
|
||||||
@@ -235,3 +235,22 @@ async def test_deploy_and_teardown_against_real_docker(repo, tmp_path, monkeypat
|
|||||||
p.unlink()
|
p.unlink()
|
||||||
# Sanity: Path roundtrip still resolvable
|
# Sanity: Path roundtrip still resolvable
|
||||||
assert isinstance(Path(str(p)), Path)
|
assert isinstance(Path(str(p)), Path)
|
||||||
|
|
||||||
|
|
||||||
|
def test_compose_path_is_absolute_and_cwd_independent(tmp_path, monkeypatch):
|
||||||
|
"""Regression: a CWD-relative compose path littered the install dir and
|
||||||
|
let teardown's unlink() miss orphans. Path must be absolute and stable
|
||||||
|
across CWD changes so write and teardown always agree."""
|
||||||
|
monkeypatch.setenv("DECNET_RUN_DIR", str(tmp_path))
|
||||||
|
tid = "abcdef1234567890"
|
||||||
|
|
||||||
|
monkeypatch.chdir(tmp_path)
|
||||||
|
p1 = _topology_compose_path(tid)
|
||||||
|
sub = tmp_path / "elsewhere"
|
||||||
|
sub.mkdir()
|
||||||
|
monkeypatch.chdir(sub)
|
||||||
|
p2 = _topology_compose_path(tid)
|
||||||
|
|
||||||
|
assert p1.is_absolute()
|
||||||
|
assert p1 == p2, "compose path must not depend on process CWD"
|
||||||
|
assert p1.parent == tmp_path
|
||||||
|
|||||||
Reference in New Issue
Block a user