Publish curated Unraid-AppOps-Gateway source from 1e4c6557cffe03959a4837cda9bc9ad6b35cf6bc
This commit is contained in:
1 parent
3edb084a91
commit
28f691b77e
3 files changed
+158
-6
No files matched your search
@@ -1,3 +1,3 @@
|
||||
# Public source export
|
||||
|
||||
This source snapshot was generated from the private canonical repository at revision `d013be0be977c530311fae02934026709d8a952f`. It contains no private Git history or operational evidence. Changes are published from the canonical repository.
|
||||
This source snapshot was generated from the private canonical repository at revision `1e4c6557cffe03959a4837cda9bc9ad6b35cf6bc`. It contains no private Git history or operational evidence. Changes are published from the canonical repository.
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"sourceRevision": "d013be0be977c530311fae02934026709d8a952f",
|
||||
"sourceRevision": "1e4c6557cffe03959a4837cda9bc9ad6b35cf6bc",
|
||||
"files": [
|
||||
{
|
||||
"path": ".dockerignore",
|
||||
@@ -1619,8 +1619,8 @@
|
||||
},
|
||||
{
|
||||
"path": "backend/tests/test_runner_build_launcher_refresh.py",
|
||||
"sha256": "887c1efb5a51e4c63eecd09a7927dfa4048e66a0dce4ceaf77b11f49f59eae5c",
|
||||
"bytes": 22199
|
||||
"sha256": "2268e8e71c8c049cfc8d98539ab09cd6db1db4acefdd7ab00187410fbc57641a",
|
||||
"bytes": 30038
|
||||
},
|
||||
{
|
||||
"path": "backend/tests/test_runner_capacity_controller.py",
|
||||
|
||||
@@ -122,7 +122,7 @@ def launcher(monkeypatch, tmp_path):
|
||||
monkeypatch.setattr(module, "_guard_state_unchanged", lambda _j: True)
|
||||
monkeypatch.setattr(module, "_fresh_recovery_host_gate", lambda: None)
|
||||
monkeypatch.setattr(module, "_resource_proof", lambda *_a: {"ready": True})
|
||||
monkeypatch.setattr(module, "verify_profile_task_images", lambda *_a: True)
|
||||
monkeypatch.setattr(module, "verify_profile_task_images", lambda *_a, **_k: True)
|
||||
monkeypatch.setattr(
|
||||
module,
|
||||
"verified_topology",
|
||||
@@ -181,7 +181,10 @@ def launcher(monkeypatch, tmp_path):
|
||||
if args[:3] == ["docker", "image", "inspect"]:
|
||||
return json.dumps([{"Id": args[-1]}])
|
||||
if args[:2] == ["docker", "inspect"]:
|
||||
result = [item for item in containers.values() if item["Id"] == args[-1]]
|
||||
result = [
|
||||
item for name, item in containers.items()
|
||||
if name in args[2:] or item["Id"] in args[2:]
|
||||
]
|
||||
if not result:
|
||||
raise module.RunnerFleetSpecializeError(
|
||||
"runner_fleet_specialization_command_failed"
|
||||
@@ -230,6 +233,155 @@ def launcher(monkeypatch, tmp_path):
|
||||
return module, containers, rows, admission, effects, model
|
||||
|
||||
|
||||
def test_refresh_uses_real_outer_image_postcondition_in_created_phase(launcher, monkeypatch):
|
||||
module, containers, rows, _, _, _ = launcher
|
||||
before = copy.deepcopy(containers)
|
||||
registrations = copy.deepcopy(rows)
|
||||
monkeypatch.setattr(
|
||||
module, "verify_profile_task_images",
|
||||
lambda profiles, **kwargs: module._verify_specialized_outer_images(profiles, **kwargs),
|
||||
)
|
||||
preflight = module._build_launcher_preflight("refresh")
|
||||
result = module._apply_build_launcher("refresh", preflight["preflightSha256"])
|
||||
assert result["status"] == "applied"
|
||||
assert rows == registrations
|
||||
for name in before:
|
||||
if name != "itworx-ci-build":
|
||||
assert containers[name] == before[name]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("change", [
|
||||
"forged_receipt", "partial_profiles", "changed_release", "wrong_stage",
|
||||
"running_candidate", "foreign_candidate_id", "wrong_candidate_image",
|
||||
"wrong_operation_label", "changed_mount", "running_backup", "changed_other_limit",
|
||||
])
|
||||
def test_created_launcher_scope_rejects_drift_and_keeps_normal_admission_blocked(launcher, monkeypatch, change):
|
||||
module, containers, _, _, effects, _ = launcher
|
||||
|
||||
def checked(profiles, **kwargs):
|
||||
receipt = module._build_launcher_receipt()
|
||||
if receipt is None or receipt["status"] != "created":
|
||||
return module._verify_specialized_outer_images(profiles, **kwargs)
|
||||
assert module._verify_specialized_outer_images(profiles) is False
|
||||
assert module.verified_topology()["ready"] is False
|
||||
assert module._verify_specialized_outer_images(profiles, **kwargs) is True
|
||||
original_containers = copy.deepcopy(containers)
|
||||
original_receipt = copy.deepcopy(receipt)
|
||||
release = sys.modules["status_server"]._require_controller_release()
|
||||
original_release = copy.deepcopy(release)
|
||||
effects_before = copy.deepcopy(effects)
|
||||
candidate = containers["itworx-ci-build"]
|
||||
scoped = dict(kwargs)
|
||||
selected = profiles
|
||||
if change == "forged_receipt":
|
||||
scoped["pending_build_launcher"] = {**receipt, "operationId": "9" * 64}
|
||||
elif change == "partial_profiles":
|
||||
selected = ("build",)
|
||||
elif change == "changed_release":
|
||||
release["sourceRevision"] = "9" * 40
|
||||
elif change == "wrong_stage":
|
||||
modified = {**receipt, "status": "prepared"}
|
||||
module._write_private_atomic(module._build_launcher_receipt_path(), module._canonical_bytes(modified))
|
||||
scoped["pending_build_launcher"] = modified
|
||||
elif change == "running_candidate":
|
||||
candidate["State"]["Running"] = True
|
||||
elif change == "foreign_candidate_id":
|
||||
candidate["Id"] = "9" * 64
|
||||
elif change == "wrong_candidate_image":
|
||||
candidate["Image"] = module.RUNNER_IMAGE_ID
|
||||
elif change == "wrong_operation_label":
|
||||
candidate["Config"]["Labels"]["tech.itworx.ci.launcher-operation"] = "9" * 64
|
||||
elif change == "changed_mount":
|
||||
candidate["Mounts"][1]["RW"] = True
|
||||
elif change == "running_backup":
|
||||
containers[receipt["backupName"]]["State"]["Running"] = True
|
||||
else:
|
||||
containers["itworx-ci-backend"]["HostConfig"]["Memory"] += 1
|
||||
try:
|
||||
assert module._verify_specialized_outer_images(selected, **scoped) is False
|
||||
assert effects == effects_before
|
||||
finally:
|
||||
containers.clear()
|
||||
containers.update(original_containers)
|
||||
release.clear()
|
||||
release.update(original_release)
|
||||
module._write_private_atomic(module._build_launcher_receipt_path(), module._canonical_bytes(original_receipt))
|
||||
return module._verify_specialized_outer_images(profiles, **kwargs)
|
||||
|
||||
monkeypatch.setattr(module, "verify_profile_task_images", checked)
|
||||
preflight = module._build_launcher_preflight("refresh")
|
||||
result = module._apply_build_launcher("refresh", preflight["preflightSha256"])
|
||||
assert result["status"] == "applied"
|
||||
|
||||
|
||||
def test_final_created_snapshot_refuses_other_runner_identity_change(launcher, monkeypatch):
|
||||
module, containers, _, _, _, _ = launcher
|
||||
|
||||
def check_then_drift(profiles, **kwargs):
|
||||
valid = module._verify_specialized_outer_images(profiles, **kwargs)
|
||||
if kwargs.get("pending_build_launcher") is not None:
|
||||
containers["itworx-ci-backend"]["Id"] = "9" * 64
|
||||
return valid
|
||||
|
||||
monkeypatch.setattr(module, "verify_profile_task_images", check_then_drift)
|
||||
preflight = module._build_launcher_preflight("refresh")
|
||||
with pytest.raises(module.RunnerFleetSpecializeError, match="runner_build_launcher_outcome_unknown"):
|
||||
module._apply_build_launcher("refresh", preflight["preflightSha256"])
|
||||
assert module._build_launcher_receipt()["status"] == "rollback_unknown"
|
||||
receipt = module._build_launcher_receipt()
|
||||
diagnostic = json.loads((module.SPECIALIZED_STATE_ROOT / ("build-launcher-failure-" + receipt["operationId"] + ".json")).read_bytes())
|
||||
assert diagnostic["failureStage"] == "final_fences"
|
||||
assert diagnostic["failureCode"] == "runner_build_launcher_recovery_fleet_changed"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("failure,expected_code", [
|
||||
("runner_build_launcher_postcondition_failed", "runner_build_launcher_postcondition_failed"),
|
||||
("synthetic_private_detail_not_for_receipts", "runner_build_launcher_internal_failure"),
|
||||
])
|
||||
def test_private_rollback_diagnostics_retain_only_finite_codes(launcher, monkeypatch, failure, expected_code):
|
||||
module, _, _, _, _, _ = launcher
|
||||
|
||||
def fail_after_creation(_profiles, **kwargs):
|
||||
if kwargs.get("pending_build_launcher") is not None:
|
||||
raise RuntimeError(failure)
|
||||
return True
|
||||
|
||||
monkeypatch.setattr(module, "verify_profile_task_images", fail_after_creation)
|
||||
preflight = module._build_launcher_preflight("refresh")
|
||||
with pytest.raises(module.RunnerFleetSpecializeError, match="runner_build_launcher_failed_rolled_back"):
|
||||
module._apply_build_launcher("refresh", preflight["preflightSha256"])
|
||||
receipt = module._build_launcher_receipt()
|
||||
assert receipt["status"] == "rolled_back"
|
||||
diagnostic = json.loads((module.SPECIALIZED_STATE_ROOT / ("build-launcher-failure-" + receipt["operationId"] + ".json")).read_bytes())
|
||||
assert diagnostic["failureStage"] == "task_images"
|
||||
assert diagnostic["failureCode"] == expected_code
|
||||
assert "failureStage" not in receipt and "failureCode" not in receipt
|
||||
assert "synthetic_private_detail_not_for_receipts" not in module._build_launcher_receipt_path().read_text()
|
||||
|
||||
|
||||
def test_diagnostic_storage_failure_does_not_prevent_guarded_rollback(launcher, monkeypatch):
|
||||
module, containers, _, _, _, _ = launcher
|
||||
before = copy.deepcopy(containers)
|
||||
original_write = module._write_private_atomic
|
||||
|
||||
def write_without_diagnostics(path, raw):
|
||||
if path.name.startswith("build-launcher-failure-"):
|
||||
raise OSError("synthetic_private_storage_detail")
|
||||
original_write(path, raw)
|
||||
|
||||
def fail_after_creation(_profiles, **kwargs):
|
||||
return kwargs.get("pending_build_launcher") is None
|
||||
|
||||
monkeypatch.setattr(module, "_write_private_atomic", write_without_diagnostics)
|
||||
monkeypatch.setattr(module, "verify_profile_task_images", fail_after_creation)
|
||||
preflight = module._build_launcher_preflight("refresh")
|
||||
with pytest.raises(module.RunnerFleetSpecializeError, match="runner_build_launcher_failed_rolled_back"):
|
||||
module._apply_build_launcher("refresh", preflight["preflightSha256"])
|
||||
assert module._build_launcher_receipt()["status"] == "rolled_back"
|
||||
assert containers == before
|
||||
assert not list(module.SPECIALIZED_STATE_ROOT.glob("build-launcher-failure-*.json"))
|
||||
|
||||
|
||||
def test_refresh_and_explicit_rollback_preserve_fleet_and_archived_model(launcher):
|
||||
module, containers, rows, _, effects, model = launcher
|
||||
before = copy.deepcopy(containers)
|
||||
|
||||
Reference in new issue
Block a user