refactor: remove leftovers from the orchestrator/gateway consolidation

Sweep for vestiges of the old combined-plane model and the pre-split shared
rootfs. Two are load-bearing, the rest are stale docs/comments:

- Bug: macOS `enumerate_active` only excluded the gateway container from the
  agent list, so after the split the orchestrator container
  (`bot-bottle-mac-orchestrator`, also `bot-bottle-`-prefixed) was enumerated as
  a phantom agent. Exclude both infra containers; test covers it.
- Dead code: the gateway `bootstrap.py` still carried an `orchestrator` daemon
  spec + `_OPT_IN_DAEMONS` + a signing-key/JWT env branch, all for the old
  combined container where the gateway process could also run the control plane.
  No backend ever requests it now — removed; the key-stripping stays as
  defense-in-depth.

Stale-comment reframes: "the/single infra container" -> the orchestrator +
gateway pair (or the specific plane); "shared rootfs / bb_role init / one
published rootfs" -> the per-plane rootfs + `role_init`; the deleted
Dockerfile.infra references in Dockerfile.orchestrator/.gateway; and the macOS
"one infra container ... same address" docstring + its now-false
share-one-address test (the planes are distinct containers with distinct
addresses).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-25 15:48:16 -04:00
parent d0d1da612e
commit cb2d778a8f
17 changed files with 103 additions and 124 deletions
@@ -69,8 +69,8 @@ def _boot_args(
pub_b64 = base64.b64encode(pubkey.encode()).decode()
args = f"{_BASE_BOOT_ARGS} {ip_arg} bb_pubkey={pub_b64}"
# `extra` carries caller-supplied cmdline params the guest init reads
# (e.g. `bb_role=orchestrator|gateway` selecting which infra plane a
# shared-rootfs infra VM runs). Agent VMs pass nothing.
# (e.g. the gateway VM's `bb_orch=<orchestrator guest IP>`). Agent VMs pass
# nothing.
return f"{args} {extra}".rstrip() if extra else args
+16 -16
View File
@@ -8,14 +8,13 @@ gateway VM never opens `bot-bottle.db` (#469), so it holds no signing key —
only the token the host hands it via `connect_to_orchestrator`.
What deliberately stays in `infra_vm` (not moved here): the plane-agnostic VM
substrate the orchestrator VM shares — booting a VM from the shared rootfs
substrate the orchestrator VM also uses — booting a VM from a per-plane rootfs
(`boot_vm`), the stable SSH keypair, the secret-push retry loop, and the PID
lifecycle — plus the pair coordinator (`ensure_running`: orchestrator-first
health gate, singleton lock, adoption/version marker). The guest-side gateway
daemon startup lives in the shared `bb_role=gateway` init branch baked into the
one published rootfs both VMs boot, so it can't live in a host-side method
either. These are the shared seam that moves to a neutral module when the
Orchestrator service lands and `infra_vm` is dissolved.
daemon startup lives in the gateway rootfs's guest init (`_gateway_init` in
`infra_vm`), so it can't live in a host-side method either. These are the shared
seam.
"""
from __future__ import annotations
@@ -33,18 +32,19 @@ from .. import util as backend_util
from . import infra_vm, netpool, util
from .gateway_transport import FirecrackerGatewayTransport
# The gateway microVM's name (the `bb_role=gateway` boot tag / run dir). Fixed
# per host — one gateway VM, shared by every agent VM.
# The gateway microVM's name (its run dir). Fixed per host — one gateway VM,
# shared by every agent VM.
GATEWAY_NAME = "bot-bottle-gateway"
# The gateway VM's slim memory ceiling (buildah is present on the shared rootfs
# but unused on the data plane) — PRD 0070 "Memory: fixed ceilings".
# The gateway VM's slim memory ceiling — the data plane carries no build
# tooling (buildah lives only on the orchestrator rootfs) — PRD 0070
# "Memory: fixed ceilings".
_GW_MEM_MIB = 2048
# The pre-minted `gateway` JWT path in the guest. The *shared* init (both planes
# boot one rootfs) waits for it before starting the data plane, so its canonical
# definition lives with that init in `infra_vm`; imported here for the push so
# the load-bearing path isn't duplicated.
# The pre-minted `gateway` JWT path in the guest. The gateway init (in
# `infra_vm`) waits for it before starting the data plane, so its canonical
# definition lives with that init; imported here for the push so the
# load-bearing path isn't duplicated.
_GUEST_GATEWAY_JWT_PATH = infra_vm._GUEST_GATEWAY_JWT_PATH
# mitmproxy writes its CA here a beat after start; agents install it to trust
# the gateway's TLS interception. Host-side only (SSH cat), so it lives here.
@@ -56,7 +56,7 @@ _CA_FETCH_TIMEOUT_SECONDS = 15.0
class FirecrackerGateway(Gateway):
"""The consolidated gateway as a Firecracker microVM on the gateway link.
The shared rootfs is built/downloaded by `infra_vm.ensure_built` (the ABC's
The gateway rootfs is built/downloaded by `infra_vm.ensure_built` (the ABC's
`ensure_built` no-op here); `connect_to_orchestrator` boots the VM resolving
policy against the orchestrator and seeds the pre-minted `gateway` token."""
@@ -94,8 +94,8 @@ class FirecrackerGateway(Gateway):
raise GatewayError(
f"cannot resolve orchestrator guest IP from {self._orchestrator_url!r}"
)
# Boot on the gateway link from the shared rootfs (bb_role=gateway), then
# push the token the init waits for before starting the data plane.
# Boot on the gateway link from the gateway rootfs, then push the token
# the init waits for before starting the data plane.
vm = infra_vm.boot_vm(
name=GATEWAY_NAME, slot=netpool.gw_slot(), run_dir=infra_vm._gw_dir(),
role="gateway", mem_mib=_GW_MEM_MIB,
@@ -8,11 +8,11 @@ signing key over SSH, and waiting for `/health`. The host CLI reaches it at its
guest IP, and so does the gateway (`bb_orch` cmdline), so `url()` == `gateway_url()`.
What deliberately stays in `infra_vm` (not moved here): the plane-agnostic VM
substrate the gateway VM also shares — booting a VM from the shared rootfs
substrate the gateway VM also uses — booting a VM from a per-plane rootfs
(`boot_vm`), the stable SSH keypair, the secret-push retry, the PID lifecycle —
plus the pair coordinator (`ensure_running`: adopt-or-boot-both under a singleton
lock with a shared version marker) and the single shared `bb_role`-branched init
baked into the one published rootfs. Those are the shared seam.
lock with a combined version marker) and the per-plane guest inits (`role_init`).
Those are the shared seam.
"""
from __future__ import annotations
@@ -30,8 +30,8 @@ from ...orchestrator.lifecycle import (
from . import firecracker_vm, infra_vm, netpool
from .infra_vm import ORCHESTRATOR_PORT
# The orchestrator microVM's name (the `bb_role=orchestrator` boot tag / run
# dir). Fixed per host — one control-plane VM.
# The orchestrator microVM's name (its run dir). Fixed per host — one
# control-plane VM.
ORCHESTRATOR_NAME = "bot-bottle-orchestrator"
# Memory ceiling (fixed at boot, demand-paged). The orchestrator keeps the build
@@ -58,9 +58,9 @@ def registry_volume_path() -> Path:
class FirecrackerOrchestrator(Orchestrator):
"""The control plane as a Firecracker microVM on the orchestrator link.
The shared rootfs is built/downloaded by `infra_vm.ensure_built` (the ABC's
`ensure_built` no-op here); `ensure_running` boots the VM, seeds the signing
key, and blocks until `/health` answers."""
The orchestrator rootfs is built/downloaded by `infra_vm.ensure_built` (the
ABC's `ensure_built` no-op here); `ensure_running` boots the VM, seeds the
signing key, and blocks until `/health` answers."""
name = ORCHESTRATOR_NAME
+2 -2
View File
@@ -258,8 +258,8 @@ def build_committed_rootfs_dir(tar_path: Path) -> Path:
def inject_guest_boot(rootfs: Path, init_script: str | None = None) -> None:
"""Drop the static dropbear and the PID-1 init into the rootfs.
`init_script` defaults to the SSH-only agent init; the infra VM
passes its own (control plane + gateway) init.
`init_script` defaults to the SSH-only agent init; each infra VM
passes its own per-plane init (orchestrator or gateway).
A committed snapshot is guest-controlled, so `bb-dropbear`/`bb-init`
may already exist as symlinks aimed at a host file (e.g. bb-init ->