Initialize Synology bind directories explicitly and preserve failed bootstrap journals
This commit is contained in:
@@ -321,3 +321,75 @@ def test_bootstrap_recovery_cleans_only_owned_prepared_transaction(tool, monkeyp
|
||||
tool.recover()
|
||||
assert tool.state["status"] == "failed"
|
||||
assert ("cleanup",) in calls and ("rm", "lock-id") in calls
|
||||
|
||||
|
||||
@pytest.mark.parametrize("status", ["failed", "prepared", "success"])
|
||||
def test_retry_journal_only_failed_matching_empty_bootstrap(tool, monkeypatch, status):
|
||||
prepare(tool, monkeypatch)
|
||||
record = {
|
||||
"kind": "bootstrap",
|
||||
"status": status,
|
||||
"candidate": tool.bootstrap_config(),
|
||||
}
|
||||
|
||||
def run(*args, **kw):
|
||||
if args[:2] == ("volume", "ls"):
|
||||
return SimpleNamespace(stdout=tool.env["PROD_STATE_VOLUME"].encode())
|
||||
return SimpleNamespace(
|
||||
stdout=json.dumps(
|
||||
[{"Labels": {"frameflow.deploy.project": tool.env["PROD_PROJECT"]}}]
|
||||
).encode()
|
||||
)
|
||||
|
||||
monkeypatch.setattr(tool, "run", run)
|
||||
monkeypatch.setattr(tool, "state_io", lambda: json.dumps(record).encode())
|
||||
if status == "failed":
|
||||
assert tool.bootstrap_check() is None
|
||||
record["candidate"]["services"]["pigway-frame-flow"]["volumes"][0]["source"] = (
|
||||
"/foreign/data"
|
||||
)
|
||||
with pytest.raises(ValueError):
|
||||
tool.bootstrap_check()
|
||||
|
||||
|
||||
def test_synology_initialization_mounts_only_existing_parents_and_creates_leaves(
|
||||
tool, monkeypatch, tmp_path
|
||||
):
|
||||
calls = []
|
||||
monkeypatch.setattr(tool, "run", lambda *a, **kw: calls.append((a, kw)))
|
||||
tool.initialize_directories()
|
||||
args, kw = calls[0]
|
||||
assert "-v" not in args and "--network" in args
|
||||
assert [args[i + 1] for i, value in enumerate(args) if value == "--mount"] == [
|
||||
"type=bind,source=/confirmed,target=/parent-data",
|
||||
"type=bind,source=/confirmed,target=/parent-config",
|
||||
]
|
||||
code = args[args.index("-c") + 1]
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
paths = [str(tmp_path / "data"), str(tmp_path / "config")]
|
||||
# Keep the production permission operations in the script; replace only UID for local test.
|
||||
code = code.replace("os.chown(p,10333,10333)", "None")
|
||||
result = subprocess.run(
|
||||
[sys.executable, "-c", code],
|
||||
input=json.dumps(paths).encode(),
|
||||
capture_output=True,
|
||||
)
|
||||
assert result.returncode == 0
|
||||
assert all(
|
||||
(tmp_path / name).stat().st_mode & 0o777 == 0o750 for name in ("data", "config")
|
||||
)
|
||||
(tmp_path / "data" / "keep").write_text("must survive")
|
||||
result = subprocess.run(
|
||||
[sys.executable, "-c", code],
|
||||
input=json.dumps(paths).encode(),
|
||||
capture_output=True,
|
||||
)
|
||||
assert (
|
||||
result.returncode != 0
|
||||
and (tmp_path / "data" / "keep").read_text() == "must survive"
|
||||
)
|
||||
tool.env["PROD_DATA_DIR"] = "/data"
|
||||
with pytest.raises(ValueError, match="NAS root"):
|
||||
tool.initialize_directories()
|
||||
|
||||
Reference in New Issue
Block a user