mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-10-15 19:32:21 +02:00
fix(runtime): preserve in-flight foreground attachment state
This commit is contained in:
@@ -452,8 +452,10 @@ def prune_foreground_publications():
|
|||||||
|
|
||||||
A dead/replaced manager cannot resume attachment. A missing receipt also
|
A dead/replaced manager cannot resume attachment. A missing receipt also
|
||||||
makes attachment impossible; publication cannot reconstruct that receipt.
|
makes attachment impossible; publication cannot reconstruct that receipt.
|
||||||
Its process tree still belongs to containment recovery; deleting a publication never signals or
|
Its process tree still belongs to containment recovery; deleting a
|
||||||
asserts tree death. Live/unverifiable managers and background history stay.
|
publication never signals or asserts tree death. Live/unverifiable managers
|
||||||
|
retain publication even after child teardown: attachment may still need it.
|
||||||
|
Background history stays intact.
|
||||||
"""
|
"""
|
||||||
from src import containment
|
from src import containment
|
||||||
from src import process_ownership
|
from src import process_ownership
|
||||||
@@ -471,13 +473,16 @@ def prune_foreground_publications():
|
|||||||
published = json.loads(path.read_text())
|
published = json.loads(path.read_text())
|
||||||
launch = ProcessLaunchResource.from_dict(published["launch"])
|
launch = ProcessLaunchResource.from_dict(published["launch"])
|
||||||
receipt = receipts.get(published["containment_id"])
|
receipt = receipts.get(published["containment_id"])
|
||||||
abandoned = receipt is not None and process_ownership.verify(receipt.get("manager_pid"), receipt.get("manager_token")) in {
|
abandoned = (receipt is not None
|
||||||
process_ownership.GONE, process_ownership.FOREIGN}
|
and type(receipt.get("manager_pid")) is int and receipt["manager_pid"] > 0
|
||||||
|
and isinstance(receipt.get("manager_token"), str) and bool(receipt["manager_token"])
|
||||||
|
and process_ownership.verify(receipt["manager_pid"], receipt["manager_token"]) in {
|
||||||
|
process_ownership.GONE, process_ownership.FOREIGN})
|
||||||
if (published.get("job") is None and path == launch_path(launch.generation)
|
if (published.get("job") is None and path == launch_path(launch.generation)
|
||||||
and (receipt is None or (
|
and (receipt is None or (
|
||||||
receipt.get("launch_generation") == launch.generation
|
receipt.get("launch_generation") == launch.generation
|
||||||
and receipt.get("id") == published["containment_id"]
|
and receipt.get("id") == published["containment_id"]
|
||||||
and ((receipt.get("release") or {}).get("dead") is True or abandoned)))):
|
and abandoned))):
|
||||||
# Already under the publication lock; no nested file lock.
|
# Already under the publication lock; no nested file lock.
|
||||||
path.unlink()
|
path.unlink()
|
||||||
retired += 1
|
retired += 1
|
||||||
|
|||||||
@@ -128,6 +128,7 @@ def test_old_generation_retirement_cannot_delete_replacement(workspace):
|
|||||||
|
|
||||||
@pytest.mark.parametrize('manager,release,retired', [
|
@pytest.mark.parametrize('manager,release,retired', [
|
||||||
(process_ownership.OWNED, False, False), (process_ownership.UNVERIFIABLE, False, False),
|
(process_ownership.OWNED, False, False), (process_ownership.UNVERIFIABLE, False, False),
|
||||||
|
(process_ownership.OWNED, True, False), (process_ownership.UNVERIFIABLE, True, False),
|
||||||
(process_ownership.GONE, False, True), (process_ownership.FOREIGN, False, True),
|
(process_ownership.GONE, False, True), (process_ownership.FOREIGN, False, True),
|
||||||
(process_ownership.GONE, True, True),
|
(process_ownership.GONE, True, True),
|
||||||
])
|
])
|
||||||
@@ -178,3 +179,14 @@ def test_unreadable_receipts_cannot_retire_live_consumers(workspace, receipt_dat
|
|||||||
containment._store_path().write_text(receipt_data)
|
containment._store_path().write_text(receipt_data)
|
||||||
assert resources.prune_foreground_publications() == 0
|
assert resources.prune_foreground_publications() == 0
|
||||||
assert resources.launch_path(launch.generation).is_file()
|
assert resources.launch_path(launch.generation).is_file()
|
||||||
|
|
||||||
|
|
||||||
|
def test_missing_manager_identity_cannot_retire_attachment(workspace, monkeypatch):
|
||||||
|
admitted = authority(workspace)
|
||||||
|
launch = resources.resolve_process_operation(admitted, ExactOperation.normalize('bash', 'printf pending'), NativeBackendResource('bash')).launch
|
||||||
|
resources.publish_launch(launch, admitted, 'receipt')
|
||||||
|
atomic_write_json(containment._store_path(), {'receipt': {'id': 'receipt',
|
||||||
|
'launch_generation': launch.generation, 'release': {'dead': True}}})
|
||||||
|
monkeypatch.setattr(process_ownership, 'verify', lambda *args: pytest.fail('Missing manager treated as observed'))
|
||||||
|
assert resources.prune_foreground_publications() == 0
|
||||||
|
assert resources.launch_path(launch.generation).is_file()
|
||||||
|
|||||||
Reference in New Issue
Block a user