diff --git a/decnet/mutator/ops.py b/decnet/mutator/ops.py index e42a77a9..013273a3 100644 --- a/decnet/mutator/ops.py +++ b/decnet/mutator/ops.py @@ -280,6 +280,7 @@ async def apply_update_decky( ``payload`` keys: ``decky`` — decky name. ``patch`` — dict merged into existing ``decky_config``. + ``services`` — replacement top-level services list. ``x``,``y`` — layout coords. """ hydrated = await _hydrated(repo, topology_id) @@ -291,6 +292,8 @@ async def apply_update_decky( merged = dict(decky["decky_config"]) merged.update(payload["patch"]) patch["decky_config"] = merged + if "services" in payload: + patch["services"] = list(payload["services"]) for key in ("x", "y"): if key in payload: patch[key] = payload[key] diff --git a/tests/topology/test_mutator.py b/tests/topology/test_mutator.py index 65508b2c..87ca7b26 100644 --- a/tests/topology/test_mutator.py +++ b/tests/topology/test_mutator.py @@ -158,6 +158,25 @@ async def test_apply_add_lan_persists(repo): assert "LAN-MUT" in names +@pytest.mark.anyio +async def test_apply_update_decky_replaces_services(repo): + """Top-level ``services`` payload key replaces the decky's services list.""" + tid = await _make_active(repo) + decky = (await repo.list_topology_deckies(tid))[0] + await apply_update_decky( + repo, tid, + { + "decky": decky["decky_config"]["name"], + "services": ["ssh", "http"], + }, + ) + updated = next( + d for d in await repo.list_topology_deckies(tid) + if d["uuid"] == decky["uuid"] + ) + assert sorted(updated["services"]) == ["http", "ssh"] + + @pytest.mark.anyio async def test_apply_rejected_on_validator_error(repo): """Unknown service name must trip the post-apply validator."""