refactor(enroll-bundle): extract bundle_builder and move DTOs to swarm models

Pure tarball construction (_build_tarball, _render_*, _iter_included,
_SYSTEMD_UNITS) moved to decnet/swarm/bundle_builder.py — no FastAPI
dependency, independently testable. EnrollBundleRequest/Response moved
to decnet/web/db/models/swarm.py alongside the other swarm DTOs.
Router drops from 504 to 260 lines; keeps only the in-memory token
registry, sweeper, and endpoints.
This commit is contained in:
2026-04-30 20:39:42 -04:00
parent e124f9e296
commit a5487eb55f
3 changed files with 252 additions and 256 deletions

View File

@@ -198,3 +198,34 @@ class SwarmHostHealth(BaseModel):
class SwarmCheckResponse(BaseModel):
results: list[SwarmHostHealth]
class EnrollBundleRequest(BaseModel):
master_host: str = PydanticField(..., min_length=1, max_length=253,
description="IP/host the agent will reach back to")
agent_name: str = PydanticField(..., pattern=r"^[a-z0-9][a-z0-9-]{0,62}$",
description="Worker name (DNS-label safe)")
with_updater: bool = PydanticField(
default=True,
description="Include updater cert bundle and auto-start decnet updater on the agent",
)
use_ipvlan: bool = PydanticField(
default=False,
description=(
"Run deckies on this agent over IPvlan L2 instead of MACVLAN. "
"Required when the agent is a VirtualBox/VMware guest bridged over Wi-Fi — "
"Wi-Fi APs bind one MAC per station, so MACVLAN's extra container MACs "
"rotate the VM's DHCP lease. Safe no-op on wired/bare-metal hosts."
),
)
services_ini: Optional[str] = PydanticField(
default=None,
description="Optional INI text shipped to the agent as /etc/decnet/services.ini",
)
class EnrollBundleResponse(BaseModel):
token: str
command: str
expires_at: datetime
host_uuid: str