diff --git a/decnet/web/db/models/topology.py b/decnet/web/db/models/topology.py index 913d610e..20e8423d 100644 --- a/decnet/web/db/models/topology.py +++ b/decnet/web/db/models/topology.py @@ -59,13 +59,6 @@ class LAN(SQLModel, table=True): docker_network_id: Optional[str] = Field(default=None) subnet: str is_dmz: bool = Field(default=False) - # Per-LAN swarm host pin. ``None`` means "fall back to - # ``Topology.target_host_uuid``; if that is also None, deploy on the - # master." A LAN is one Docker bridge — bridges don't span hosts — - # so a non-null value forces every decky in this LAN onto that host. - host_uuid: Optional[str] = Field( - default=None, foreign_key="swarm_hosts.uuid", index=True - ) # Canvas layout coordinates (set by the web editor). Nullable so # generator-emitted LANs don't need auto-layout at generation time. x: Optional[float] = Field(default=None) @@ -232,7 +225,6 @@ class LANRow(BaseModel): subnet: str is_dmz: bool = False docker_network_id: Optional[str] = None - host_uuid: Optional[str] = None x: Optional[float] = None y: Optional[float] = None @@ -288,7 +280,6 @@ class LANCreateRequest(BaseModel): name: str = PydanticField(..., min_length=1, max_length=64) subnet: Optional[str] = None is_dmz: bool = False - host_uuid: Optional[str] = None x: Optional[float] = None y: Optional[float] = None expected_version: Optional[int] = None @@ -298,7 +289,6 @@ class LANUpdateRequest(BaseModel): name: Optional[str] = None subnet: Optional[str] = None is_dmz: Optional[bool] = None - host_uuid: Optional[str] = None x: Optional[float] = None y: Optional[float] = None expected_version: Optional[int] = None diff --git a/decnet/web/router/topology/api_lan_crud.py b/decnet/web/router/topology/api_lan_crud.py index 60eb8ef8..ae15d394 100644 --- a/decnet/web/router/topology/api_lan_crud.py +++ b/decnet/web/router/topology/api_lan_crud.py @@ -57,20 +57,11 @@ async def api_create_lan( ) subnet = allocator.next_free() - if body.host_uuid is not None: - host = await repo.get_swarm_host_by_uuid(body.host_uuid) - if host is None: - raise HTTPException( - status_code=400, - detail=f"swarm host {body.host_uuid!r} not found", - ) - payload = { "topology_id": topology_id, "name": body.name, "subnet": subnet, "is_dmz": body.is_dmz, - "host_uuid": body.host_uuid, "x": body.x, "y": body.y, } @@ -111,13 +102,6 @@ async def api_update_lan( await assert_pending_or_409(topology_id) fields = body.model_dump(exclude_unset=True, exclude={"expected_version"}) - if "host_uuid" in fields and fields["host_uuid"] is not None: - host = await repo.get_swarm_host_by_uuid(fields["host_uuid"]) - if host is None: - raise HTTPException( - status_code=400, - detail=f"swarm host {fields['host_uuid']!r} not found", - ) try: await repo.update_lan( lan_id, diff --git a/tests/api/topology/test_child_crud.py b/tests/api/topology/test_child_crud.py index 1cee11ae..b8c36375 100644 --- a/tests/api/topology/test_child_crud.py +++ b/tests/api/topology/test_child_crud.py @@ -111,78 +111,6 @@ async def test_lan_requires_admin(client, viewer_token): assert r.status_code == 403 -# ── LAN host_uuid (per-Net SWARM assignment) ────────────────────── - - -async def _enroll_host(uuid: str = "h-test", name: str = "test-host") -> str: - await _repo.add_swarm_host( - { - "uuid": uuid, - "name": name, - "address": "10.99.0.2", - "agent_port": 8765, - "status": "active", - "client_cert_fingerprint": "a" * 64, - "cert_bundle_path": "/tmp/test", - } - ) - return uuid - - -@pytest.mark.anyio -async def test_lan_create_with_host_uuid(client, auth_token): - topology_id = await _seed("lan-host-create") - host_uuid = await _enroll_host("h-create", "host-create") - r = await client.post( - f"{_V1}/{topology_id}/lans", - json={"name": "remote-lan", "host_uuid": host_uuid}, - headers=_hdr(auth_token), - ) - assert r.status_code == 201, r.text - assert r.json()["host_uuid"] == host_uuid - - -@pytest.mark.anyio -async def test_lan_create_rejects_unknown_host(client, auth_token): - topology_id = await _seed("lan-host-bad") - r = await client.post( - f"{_V1}/{topology_id}/lans", - json={"name": "ghost-lan", "host_uuid": "ghost-uuid"}, - headers=_hdr(auth_token), - ) - assert r.status_code == 400 - - -@pytest.mark.anyio -async def test_lan_patch_host_uuid(client, auth_token): - topology_id = await _seed("lan-host-patch") - host_uuid = await _enroll_host("h-patch", "host-patch") - lans = await _repo.list_lans_for_topology(topology_id) - lan_id = lans[0]["id"] - - r = await client.patch( - f"{_V1}/{topology_id}/lans/{lan_id}", - json={"host_uuid": host_uuid}, - headers=_hdr(auth_token), - ) - assert r.status_code == 200, r.text - assert r.json()["host_uuid"] == host_uuid - - -@pytest.mark.anyio -async def test_lan_patch_rejects_unknown_host(client, auth_token): - topology_id = await _seed("lan-host-patch-bad") - lans = await _repo.list_lans_for_topology(topology_id) - lan_id = lans[0]["id"] - - r = await client.patch( - f"{_V1}/{topology_id}/lans/{lan_id}", - json={"host_uuid": "ghost-uuid"}, - headers=_hdr(auth_token), - ) - assert r.status_code == 400 - - # ── Decky CRUD ────────────────────────────────────────────────────