fix: pct_create fast gateway pre-flight + bridge param (real root cause of TypeType's DNS failures)
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled

Investigated why the operator couldn't get past "no DNS/connectivity" across
multiple retries even after Nomos correctly diagnosed and fixed the gateway
(192.168.8.1 -> 192.168.8.2). It still failed. Root cause, confirmed from
strong's own documented network topology: on `strong`, vmbr0 physically
bridges only to 192.168.178.0/24 — the 192.168.8.0/24 service network is
reached via a Fritz!Box static route, not a local bridge. A container
attached to vmbr0 can never reach a 192.168.8.x gateway no matter which
address in that range is picked; ARP for it just gets silently dropped
(matching the earlier hang symptom). The gateway was never the problem — the
bridge was. 192.168.8.0/24 is also segmented into /28 blocks each with their
own gateway (192.168.8.2 is only the .0-.15 block's gateway), so even a
correct bridge with a copy-pasted gateway from a different block would still
fail.

No amount of retrying with a different gateway guess could have fixed this —
the missing fact (which bridge reaches which subnet, and the per-/28 gateway)
isn't inferable from the subnet alone.

- pct_create gets a `bridge` param (was hardcoded to vmbr0) so a correct
  bridge can actually be requested once known.
- Fast pre-flight: for any static IP, ping the gateway from the target HOST
  before creating anything. Was: a bad config took a multi-minute hang (or,
  after last commit's timeout fix, ~2min) before failing. Now: ~2 seconds,
  with a message that explicitly says not to guess a different gateway in
  the same subnet — find a real neighbor's config or use DHCP.
- SOUL.md: DHCP is now framed as the default, not a fallback; static IP
  requires finding an existing LXC on the same host in the same /28 and
  copying its bridge+gateway verbatim — inventing one is explicitly called
  out as the failure mode that caused this exact incident.
- MCP tool schema: pct_create's params description now documents `bridge`
  and the neighbor-copy rule directly in what the model reads at call time,
  not just in SOUL.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-10 11:48:06 +02:00
parent 8950bada44
commit 82b0ad2298
3 changed files with 58 additions and 6 deletions

View File

@@ -100,9 +100,30 @@ Before calling `request_execution`:
created in the DB with `hosts` relationships and `state: provisioning`.
- **vmid**: omit or set 0 — a free cluster id is assigned automatically. Never reuse an
existing container's id.
- **networking**: prefer `"ip":"dhcp"` unless the operator needs a fixed address; DHCP
yields a working DNS resolver. If you set a static CIDR, the provisioner self-heals DNS
to a public resolver when the gateway can't resolve, but DHCP is more reliable.
- **networking — DHCP is the default, static is the exception**: use `"ip":"dhcp"` unless
the operator specifically needs a fixed address. DHCP is proven reliable and always gets
a real, routable IP. **A static IP is not a formula you can compute from the subnet
alone.** Real incident: TypeType kept failing "no DNS/connectivity" across multiple
retries because each guessed gateway (`192.168.8.1`, then `192.168.8.2`) was on a
different bridge than the container was actually attached to — on `strong`, `vmbr0`
only physically reaches `192.168.178.0/24`; `192.168.8.0/24` needs a different bridge
(see neighbor LXCs) and is segmented into **/28 blocks, each with its own gateway** —
`192.168.8.2` is only the gateway for the `.0.15` block, not the whole `/24`. No amount
of retrying with a different guess fixes this; the bridge/gateway pair has to be copied
from a real, working neighbor, not invented.
- **Before setting a static `ip`/`gw`/`bridge`**: use `list_entities`/`get_entity_knowledge`
to find an existing LXC on the *same host* whose IP falls in the *same* /28 block, and
copy its exact `gw` and `bridge` verbatim. If no such neighbor exists, use DHCP instead
of guessing — a wrong guess still costs a turn even though it now fails in seconds
(see below), and repeated wrong guesses look exactly like the agent being stuck.
- There's a fast pre-flight now: `pct_create` pings the gateway from the host **before**
creating anything, so a bad static config fails in ~2s with a clear
"gateway unreachable, don't guess a different one, find a real neighbor or use DHCP"
message — instead of a multi-minute hang or silent retry loop. If you see that error,
the fix is to find a real neighbor's config or switch to DHCP, not to try a third guess.
- If you set a static CIDR anyway and the *DNS resolver itself* (not the gateway) is the
problem, the provisioner self-heals to a public resolver — but that only helps once the
gateway/bridge are actually correct.
- **Docker**: `docker-compose-plugin` is NOT in Debian's repos — do not put it in
`services`. For Docker, put `docker.io` in `services` (it provides the engine) and, if
you need compose v2, install it in `post_install` from Docker's official convenience