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
|
# 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,
|
"schemaVersion": 1,
|
||||||
"sourceRevision": "d013be0be977c530311fae02934026709d8a952f",
|
"sourceRevision": "1e4c6557cffe03959a4837cda9bc9ad6b35cf6bc",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"path": ".dockerignore",
|
"path": ".dockerignore",
|
||||||
@@ -1619,8 +1619,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "backend/tests/test_runner_build_launcher_refresh.py",
|
"path": "backend/tests/test_runner_build_launcher_refresh.py",
|
||||||
"sha256": "887c1efb5a51e4c63eecd09a7927dfa4048e66a0dce4ceaf77b11f49f59eae5c",
|
"sha256": "2268e8e71c8c049cfc8d98539ab09cd6db1db4acefdd7ab00187410fbc57641a",
|
||||||
"bytes": 22199
|
"bytes": 30038
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "backend/tests/test_runner_capacity_controller.py",
|
"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, "_guard_state_unchanged", lambda _j: True)
|
||||||
monkeypatch.setattr(module, "_fresh_recovery_host_gate", lambda: None)
|
monkeypatch.setattr(module, "_fresh_recovery_host_gate", lambda: None)
|
||||||
monkeypatch.setattr(module, "_resource_proof", lambda *_a: {"ready": True})
|
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(
|
monkeypatch.setattr(
|
||||||
module,
|
module,
|
||||||
"verified_topology",
|
"verified_topology",
|
||||||
@@ -181,7 +181,10 @@ def launcher(monkeypatch, tmp_path):
|
|||||||
if args[:3] == ["docker", "image", "inspect"]:
|
if args[:3] == ["docker", "image", "inspect"]:
|
||||||
return json.dumps([{"Id": args[-1]}])
|
return json.dumps([{"Id": args[-1]}])
|
||||||
if args[:2] == ["docker", "inspect"]:
|
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:
|
if not result:
|
||||||
raise module.RunnerFleetSpecializeError(
|
raise module.RunnerFleetSpecializeError(
|
||||||
"runner_fleet_specialization_command_failed"
|
"runner_fleet_specialization_command_failed"
|
||||||
@@ -230,6 +233,155 @@ def launcher(monkeypatch, tmp_path):
|
|||||||
return module, containers, rows, admission, effects, model
|
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):
|
def test_refresh_and_explicit_rollback_preserve_fleet_and_archived_model(launcher):
|
||||||
module, containers, rows, _, effects, model = launcher
|
module, containers, rows, _, effects, model = launcher
|
||||||
before = copy.deepcopy(containers)
|
before = copy.deepcopy(containers)
|
||||||
|
|||||||
Reference in new issue
Block a user