Commit Graph
14682 Commits
Author SHA1 Message Date
evangelostsak 955c46f6b1 test(ci): carry the mesh axis through a retrigger
The fixture holds one value per dispatch input, distinct from its default, so
an input the retrigger drops shows up as a missing key. Adding the input
without adding it here made that check fail on its own absence.
2026-09-26 08:54:12 +02:00
evangelostsak c2400dc0d7 feat(ci): pass INFINITO_VPN through to the generated env 2026-09-26 08:31:32 +02:00
evangelostsak a871b8ecb0 feat(ci): register INFINITO_VPN 2026-09-26 08:31:32 +02:00
evangelostsak f224425465 feat(ci): hand the run's mesh mode to the matrix builder 2026-09-26 08:31:23 +02:00
evangelostsak 6b3a46cc5f feat(ci): carry the mesh axis to the deploy chunks
Declared once and passed to the four chunks only; validation does not take it,
because a selection pin is checked against axes the row offers, not against
the run's own.
2026-09-26 08:31:23 +02:00
evangelostsak c8107ceb46 feat(ci): offer the mesh axis as a dispatch choice
It was only pinnable per token, so there was no run-wide control and nothing
for the GitHub UI to show. Now a dropdown beside the tor one, and a run that
holds it says so in the title.
2026-09-26 08:31:23 +02:00
evangelostsak f0bd7b1bb0 feat(ci): accept --vpn when building the matrix 2026-09-26 08:31:11 +02:00
evangelostsak 89ab678a19 feat(ci): take the run's mesh mode when assigning rows
Also moves the title codec to label.py and re-exports it, which is what keeps
the file under the line cap.
2026-09-26 08:31:11 +02:00
evangelostsak 85e9112409 refactor(ci): split the job-title codec out of the assigner
Reading a title back into its axes is the inverse of building one, and it kept
axes.py over the 500-line cap once the mesh axis landed. The names stay
importable from axes so no consumer moves.
2026-09-26 08:31:01 +02:00
evangelostsak 4be2a381ab feat(ci): let a run hold the mesh axis on one side
auto rotates, enforced meshes every swarm row, disabled meshes none. No
exclusive: every swarm row can take the mesh, so there is nothing to drop.

A run that holds the axis outranks a per-token pin, because an operator who
asked for a whole sweep on one side means it.
2026-09-26 08:30:44 +02:00
evangelostsak 997b2f5091 fix(ci): count the mesh state as a narrowing axis
Without it two tokens differing only in the mesh state compare equal and
collapse into one, and a bare role&vpn reads as narrowing nothing.
2026-09-26 02:11:40 +02:00
evangelostsak 14ba824585 Merge origin/main into feature/svc-net-wireguard
Six commits, all Docker image version bumps for web-app-erpnext,
web-app-gitlab and web-app-matomo. No conflicts.

The MCP audit report needed no regeneration this time: the lint gate that
caught the stale baserow row twice is green as merged.
2026-09-26 01:42:29 +02:00
evangelostsak 1e59291866 docs(requirements): rewrite the transport and gate for the mesh axis
The controller is now a mesh member rather than staying off it behind a
gateway hop, and the two-phase seam falls between the two deploy passes the
round already had, so the second runs over the tunnel at no extra CI cost.

The gate and the axis are separated: whether a swarm deploy carries the mesh
is decided per run, and when it does the mesh is mandatory. Swarm and the mesh
are independent, so an off run omits the role entirely and proves swarm still
works with no mesh logic in the path.

The MTU is measured rather than declared. Criteria follow: three new ones for
the transport, two for the axis arms, one for the tooling, and the MTU one is
unchecked again because what it claimed has changed.
2026-09-26 01:34:14 +02:00
infinito-nexus-updater[bot] 36c9998e0b update(images): update Docker image versions (svc-ai-ollama) 2026-09-25 23:30:54 +00:00
evangelostsak 7be37c2369 feat(swarm-test): run the update pass over the mesh
The round already had two passes. The first brings the mesh up over the
container connection; the inventory is then switched to the mesh addresses and
the second pass runs over the tunnel, so no extra round and no extra CI time.
A full deploy of every role over the mesh is a stronger proof than a narrow
bootstrap round would have been.
2026-09-26 01:27:19 +02:00
evangelostsak db05ccc264 feat(swarm-test): put the controller on the mesh with a local connection
It runs the role like any member, but it drives the deploy rather than being
deployed to, so it keeps a local connection while the nodes keep the container
one.
2026-09-26 01:27:19 +02:00
evangelostsak a170ccb4a3 feat(mesh): expose the controller through the writer CLI 2026-09-26 01:27:19 +02:00
evangelostsak 435d839ac5 feat(mesh): admit the Ansible controller as a spoke
Named rather than resolved from a group: the controller is not a swarm member
and has no role group, and inventing one would put a non-role name into
group_names where every service and placement lookup would special-case it.
2026-09-26 01:27:07 +02:00
evangelostsak 5ae72d3b88 test(mesh): cover the controller spoke and the transport switch
Pins the two failure modes the design turns on: a host with no mesh address is
left reachable rather than stranded, and an address is only read from the host
that owns it, because the swarm reset mirrors one node's host_vars over every
other.
2026-09-26 01:27:07 +02:00
evangelostsak c471940798 feat(mesh): move the Ansible transport onto the mesh
The first pass of a deploy reaches the hosts however it can, because no tunnel
exists yet and that pass is what creates one. Every pass after it connects
over the mesh, which is what makes the mesh load-bearing rather than merely
present: a broken tunnel then fails the deploy at the connection, and no role
can quietly fall back to the underlay it was supposed to stop using.

A separate step rather than a fact set during the play, because a play cannot
change the transport it is already running over. A host holding no address on
the mesh is left alone -- rewriting it would strand a host that was
reachable.
2026-09-26 01:26:53 +02:00
evangelostsak 3a990fcc46 feat(svc-storage-nfs-server): admit every mesh pool, not just one 2026-09-26 01:16:31 +02:00
evangelostsak 64f710c6a2 feat(svc-net-wireguard): expose the mesh pools as a list
A consumer that admits mesh traffic needs every range a member can arrive
from, so a deployment carving its meshes from more than one pool extends this
rather than each consumer.
2026-09-26 01:16:31 +02:00
evangelostsak 7e1085f7f5 docs: list the WireGuard role in the overview table
The table was stale, not filtered -- the role is invokable and its lifecycle
is inside the tested envelope.
2026-09-26 01:14:10 +02:00
evangelostsak d8307d38d5 docs(svc-net-wireguard): point the role at its upstream
The blanket info-media nocheck claimed WireGuard has no consumer-facing
upstream, which is wrong: wireguard.com is the project's own site and the
README table renders it as the role's link.
2026-09-26 01:14:10 +02:00
evangelostsak 140c04d47f refactor(svc-net-wireguard): probe against the measured overlay MTU 2026-09-25 22:35:29 +02:00
evangelostsak 3043f6607d refactor(svc-net-wireguard): render the shared key and the measured MTU 2026-09-25 22:35:29 +02:00
evangelostsak e2e09eda06 refactor(svc-net-wireguard): one private key, measured MTUs, no dead var
WIREGUARD_QUICK_BINARY went with the install gate that used it.
2026-09-25 22:35:29 +02:00
evangelostsak 188e4bd307 refactor(svc-net-wireguard): collapse the per-mesh keys into one 2026-09-25 22:35:22 +02:00
evangelostsak 978c0eeb28 refactor(mesh): one key per host, not one per mesh
A host presents the same identity on every plane it belongs to, so the hub no
longer carries two identities and the writer has one credential to keep in
step. A member already keyed by an earlier mesh keeps that key instead of
minting a second one.
2026-09-25 22:35:22 +02:00
evangelostsak e337e2f51f feat(mesh): follow the pool reference into its SPOT
The pool is declared once under NETWORK_* and referenced from the mesh file.
Ansible resolves that at play time; this writer runs before the play, so it
follows the one hop rather than duplicating the value.
2026-09-25 22:35:17 +02:00
evangelostsak 8612e4d922 refactor(svc-net-wireguard): take the pool from the network SPOT, drop the fixed MTUs
The MTUs are measured per host now, so a declared pair could only contradict
the measurement.
2026-09-25 22:35:13 +02:00
evangelostsak 7cea09310b feat(network): declare the mesh pool beside every other range
NETWORK_* is the SPOT for what the platform allocates, and an overlap is only
catchable where the ranges sit together.
2026-09-25 22:35:13 +02:00
evangelostsak 041805f1ea fix(svc-net-wireguard): reconfigure a live interface instead of restarting it
wg-quick down on the interface Ansible is connected over kills the session
carrying the play, and the up that would restore it never runs. syncconf
applies new keys and peers to the live interface, so a rotated mesh converges
without dropping the connection that is rotating it.

Latent until now only because the deploy still runs over the underlay.
2026-09-25 22:35:07 +02:00
evangelostsak 10e99b0f39 feat(svc-net-wireguard): provision the tooling and measure the MTU
The install no longer skips when wg-quick happens to exist: the node image
stopped pre-baking it, so the role is what puts it there.

The tunnel and overlay MTUs are now measured with automtu against the hub's
underlay endpoint rather than hardcoded. Fixed values contradict the MTU
automtu already derives for the docker daemon, and the mesh addresses cannot
be probed because the interface those MTUs configure is not up yet.
2026-09-25 22:35:01 +02:00
evangelostsak acd6b17205 refactor(sys-svc-container): take the shared ids from the root package file 2026-09-25 22:34:55 +02:00
evangelostsak f5c19a6b46 refactor(packages): share the iproute and iputils ids
Both sys-svc-container and svc-net-wireguard need them, and a role may only
install ids from its own file or from the shared root one.
2026-09-25 22:34:55 +02:00
evangelostsak c7ec4292d9 fix(swarm-test): stop pre-baking the mesh tooling into the node image
Shipping wireguard-tools in the image meant the role's own install path was
never exercised, which is the thing the test exists to prove. The role now
provisions it.
2026-09-25 22:34:48 +02:00
evangelostsak 382cb77b56 fix(swarm): drop the dependency on the WireGuard service
Swarm and the mesh are independent: a production swarm can run in one isolated
physical environment, and the mesh exists to join clusters that are physically
separated. Declaring the service required made every swarm deploy pull the
mesh in, which is what the axis now decides per run.
2026-09-25 22:34:43 +02:00
evangelostsak e5de9675f3 feat(swarm-test): skip the mesh writer when the axis is off
The groups it resolves members from are absent, so writing is a no-op that
would otherwise fail on an empty mesh.
2026-09-25 22:34:37 +02:00
evangelostsak c400866fc2 feat(swarm-test): place the mesh role only when the axis asks for it
With the axis off the role is left out of both inventories entirely rather
than deployed disabled, so that arm proves swarm works with no mesh logic
anywhere in the path.
2026-09-25 22:34:37 +02:00
evangelostsak 68651019a9 fix(swarm-test): carry the mesh state into the matrix, drop the disable workaround
SWARM_REQUIRED_SERVICES no longer force-keeps wireguard: with the axis off the
role is absent from the inventory, so there is no disabled-service conflict to
work around.
2026-09-25 22:34:32 +02:00
evangelostsak 4e4c68ac3f feat(ci): pass INFINITO_SWARM_VPN through to the generated env 2026-09-25 22:34:32 +02:00
evangelostsak 7d38b856eb feat(ci): register INFINITO_SWARM_VPN
The drill reads it to decide whether the mesh is part of this deploy.
2026-09-25 22:34:26 +02:00
evangelostsak cba50eae68 feat(ci): hand the mesh state to the swarm drill 2026-09-25 22:34:26 +02:00
evangelostsak fb2fb0e55c test(ci): cover the mesh axis
A fully pinned priority row now pins the mesh state too, and a priority row
with more combinations than the distro pool has members wraps the rotation
instead of holding one distribution per combination.
2026-09-25 22:34:21 +02:00
evangelostsak 6628bc8eb0 fix(ci): let the failure reporter find a meshed run's artifacts
The slug it rebuilds gained the mesh state, so without it the reporter looked
for an artifact name no job uploads.
2026-09-25 22:34:16 +02:00
evangelostsak 61d5206e3b feat(ci): pin the mesh state from a selection token
role&vpn / role&direct, and the same state read back off a pasted job title.
Own separator rather than more + words: + is the onion axis, and one
separator meaning two things could not be read back unambiguously.
2026-09-25 22:34:09 +02:00
evangelostsak 3128d74ba5 feat(ci): assign the mesh axis to every deploy row
Entries carry vpn, labels carry the glyph, and the artifact slug carries the
state so a meshed and a direct run of one row cannot collide on one artifact
name. Priority rows cover both states; compose never takes the axis.
2026-09-25 22:34:04 +02:00
evangelostsak edf28ac245 feat(ci): give the mesh axis its glyph pair
🔒 meshed, 🔓 direct. Neither carries a variation selector, which the token
parser strips before matching glyphs off a pasted job title.
2026-09-25 22:33:59 +02:00
evangelostsak 6391761c05 feat(ci): add the WireGuard mesh deploy axis
A swarm deploy runs either over the mesh or straight over the underlay, and
both have to keep working: the mesh joins physically separated clusters, so a
single-site swarm has no use for it and must not depend on it.

Quarters on sweep // 4 so it flips in step with neither the mode rotation nor
the onion, and a row walks every mode/tor/vpn combination over eight sweeps.
2026-09-25 22:33:55 +02:00