refactor(backend): rename consolidated_launch -> infra_launch (0081 review)

Mechanical rename addressing review 6141 on #519: "consolidated launch" was
unclear about what it composes. Rename the per-backend module
`consolidated_launch.py` -> `infra_launch.py` and the error
`ConsolidatedLaunchError` -> `InfraLaunchError` across all three backends and
their callers/tests. Unify the three identical per-backend error classes into
one `InfraLaunchError` defined in `backend/base.py` (re-exported by each
`infra_launch`) so the base backend can raise and catch a single shared type —
groundwork for the base owning the gateway-attach flow.

Add a glossary entry defining **infra** = the per-host gateway + orchestrator
service pair every bottle attaches to.

No behavior change.

Refs #516, #519.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-27 01:14:14 +00:00
parent de80aafb1f
commit 4f2ccaed29
19 changed files with 61 additions and 54 deletions
+6
View File
@@ -264,6 +264,12 @@ PlanT = TypeVar("PlanT", bound=BottlePlan)
CleanupT = TypeVar("CleanupT", bound=BottleCleanupPlan)
class InfraLaunchError(RuntimeError):
"""A per-host infra (gateway + orchestrator) launch/reconcile step could not
complete. Shared across backends so the base backend can raise + catch one
type; each backend's ``infra_launch`` module re-exports it."""
@dataclass(frozen=True)
class BottleImages:
"""Resolved image references (or artifact paths) for a bottle launch.
+1 -1
View File
@@ -142,5 +142,5 @@ class DockerBottleBackend(BottleBackend["DockerBottlePlan", "DockerBottleCleanup
return _enumerate.enumerate_active()
def attach_bottled_agents_to_gateway(self) -> None:
from .consolidated_launch import attach_bottled_agents_to_gateway
from .infra_launch import attach_bottled_agents_to_gateway
attach_bottled_agents_to_gateway()
@@ -25,16 +25,13 @@ from ...gateway import GATEWAY_NETWORK
from .infra import INFRA_NAME, DockerInfraService
from ...orchestrator.store.secret_store import ENV_VAR_SECRET_NAME
from ...orchestrator.reprovision import reprovision_bottles
from ..base import InfraLaunchError
from ..provision_bottle import deprovision_bottle, provision_bottle
from ..util import AGENT_CA_PATH
from .gateway_transport import DockerGatewayTransport
from .gateway_net import next_free_ip
class ConsolidatedLaunchError(RuntimeError):
"""The consolidated register/provision sequence could not complete."""
@dataclass(frozen=True)
class LaunchContext:
"""What the agent container needs to join the shared gateway."""
@@ -56,7 +53,7 @@ def _network_cidr(network: str) -> str:
])
cidr = proc.stdout.strip()
if proc.returncode != 0 or not cidr:
raise ConsolidatedLaunchError(
raise InfraLaunchError(
f"gateway network {network} has no subnet: {proc.stderr.strip()}"
)
return cidr
@@ -80,13 +77,13 @@ def _push_ca_to_container(container: str, ca_pem: str) -> None:
"""Replace one running agent container's trusted gateway CA with `ca_pem`
and rebuild its trust store via `docker cp` + `docker exec`. Unconditional
install there is one gateway, so no fingerprint match is needed. Raises
`ConsolidatedLaunchError` on failure."""
`InfraLaunchError` on failure."""
mkdir = run_docker(
["docker", "exec", container, "mkdir", "-p",
"/usr/local/share/ca-certificates"]
)
if mkdir.returncode != 0:
raise ConsolidatedLaunchError(
raise InfraLaunchError(
f"CA push to {container} failed (mkdir): {mkdir.stderr.strip()}"
)
with tempfile.NamedTemporaryFile("w", suffix=".crt") as tmp:
@@ -94,7 +91,7 @@ def _push_ca_to_container(container: str, ca_pem: str) -> None:
tmp.flush()
cp = run_docker(["docker", "cp", tmp.name, f"{container}:{AGENT_CA_PATH}"])
if cp.returncode != 0:
raise ConsolidatedLaunchError(
raise InfraLaunchError(
f"CA push to {container} failed (cp): {cp.stderr.strip()}"
)
ex = run_docker(
@@ -102,7 +99,7 @@ def _push_ca_to_container(container: str, ca_pem: str) -> None:
f"chmod 644 {AGENT_CA_PATH} && update-ca-certificates"]
)
if ex.returncode != 0:
raise ConsolidatedLaunchError(
raise InfraLaunchError(
f"CA push to {container} failed (update-ca-certificates): "
f"{ex.stderr.strip()}"
)
@@ -138,7 +135,7 @@ def attach_bottled_agents_to_gateway(
try:
_push_ca_to_container(name, ca_pem)
reconciled += 1
except (OSError, ConsolidatedLaunchError) as exc:
except (OSError, InfraLaunchError) as exc:
log.info(f"CA reconcile skipped for {name}: {exc}")
if reconciled:
log.info(
@@ -255,5 +252,5 @@ __all__ = [
"launch_consolidated",
"attach_bottled_agents_to_gateway",
"deprovision_consolidated",
"ConsolidatedLaunchError",
"InfraLaunchError",
]
+1 -1
View File
@@ -61,7 +61,7 @@ from .compose import (
)
from .consolidated_compose import consolidated_agent_compose
from ...orchestrator.store.config_store import resolve_teardown_timeout
from .consolidated_launch import launch_consolidated, deprovision_consolidated
from .infra_launch import launch_consolidated, deprovision_consolidated
from .infra import INFRA_NAME
from .gateway import DockerGateway
from ... import resources
+1 -1
View File
@@ -120,7 +120,7 @@ class FirecrackerBottleBackend(
return _enumerate.enumerate_active()
def attach_bottled_agents_to_gateway(self) -> None:
from .consolidated_launch import attach_bottled_agents_to_gateway
from .infra_launch import attach_bottled_agents_to_gateway
attach_bottled_agents_to_gateway()
def supervise_mcp_url(self, plan: FirecrackerBottlePlan) -> str:
@@ -41,6 +41,7 @@ from ...orchestrator.lifecycle import (
)
from ...orchestrator.reprovision import reprovision_bottles
from ...orchestrator.store.secret_store import ENV_VAR_SECRET_NAME
from ..base import InfraLaunchError
from ..provision_bottle import deprovision_bottle, provision_bottle
from ..util import AGENT_CA_PATH
from . import cleanup, util
@@ -50,10 +51,6 @@ from .infra import FirecrackerInfraService
_ENV_VAR_SECRET_PATH = "/run/bot-bottle/env-var-secret"
class ConsolidatedLaunchError(RuntimeError):
"""The consolidated register/provision sequence could not complete."""
@dataclass(frozen=True)
class LaunchContext:
"""What the Firecracker launch needs from the consolidated sequence."""
@@ -85,7 +82,7 @@ def persist_env_var_secret(private_key: Path, guest_ip: str, secret: str) -> Non
input=secret, capture_output=True, text=True, check=False,
)
if proc.returncode != 0:
raise ConsolidatedLaunchError(
raise InfraLaunchError(
f"failed to persist {ENV_VAR_SECRET_NAME} in agent VM: "
f"{proc.stderr.strip() or '<no stderr>'}"
)
@@ -95,7 +92,7 @@ def _push_gateway_ca_to_agent(private_key: Path, guest_ip: str, ca_pem: str) ->
"""Replace one running agent VM's trusted gateway CA with `ca_pem` and
rebuild its trust store over SSH. Unconditional install there is one
gateway, so no fingerprint match is needed. Bare-pipe input keeps the cert
off argv. Raises `ConsolidatedLaunchError` on failure."""
off argv. Raises `InfraLaunchError` on failure."""
install = (
"umask 022; mkdir -p /usr/local/share/ca-certificates && "
f"cat > {AGENT_CA_PATH} && chmod 644 {AGENT_CA_PATH} && "
@@ -106,7 +103,7 @@ def _push_gateway_ca_to_agent(private_key: Path, guest_ip: str, ca_pem: str) ->
input=ca_pem, capture_output=True, text=True, check=False,
)
if proc.returncode != 0:
raise ConsolidatedLaunchError(
raise InfraLaunchError(
f"CA push to {guest_ip} failed: "
f"{proc.stderr.strip() or '<no stderr>'}"
)
@@ -135,7 +132,7 @@ def attach_bottled_agents_to_gateway() -> None:
try:
_push_gateway_ca_to_agent(private_key, guest_ip, ca_pem)
reconciled += 1
except (OSError, ConsolidatedLaunchError) as exc:
except (OSError, InfraLaunchError) as exc:
info(f"CA reconcile skipped for {guest_ip}: {exc}")
if reconciled:
info(f"reconciled gateway CA into {reconciled} running Firecracker bottle(s)")
@@ -215,6 +212,6 @@ __all__ = [
"launch_consolidated",
"attach_bottled_agents_to_gateway",
"deprovision_consolidated",
"ConsolidatedLaunchError",
"InfraLaunchError",
"OrchestratorStartError",
]
+1 -1
View File
@@ -51,7 +51,7 @@ from .bottle import FirecrackerBottle
from .bottle_plan import FirecrackerBottlePlan
from ...orchestrator.store.config_store import resolve_teardown_timeout
from ...orchestrator.store.secret_store import ENV_VAR_SECRET_NAME
from .consolidated_launch import (
from .infra_launch import (
launch_consolidated,
persist_env_var_secret,
deprovision_consolidated,
@@ -118,7 +118,7 @@ class MacosContainerBottleBackend(
return _enumerate.enumerate_active()
def attach_bottled_agents_to_gateway(self) -> None:
from .consolidated_launch import attach_bottled_agents_to_gateway
from .infra_launch import attach_bottled_agents_to_gateway
attach_bottled_agents_to_gateway()
def supervise_mcp_url(self, plan: MacosContainerBottlePlan) -> str:
@@ -43,6 +43,7 @@ from ...log import info
from ...orchestrator.client import OrchestratorClient, OrchestratorClientError
from ...orchestrator.reprovision import reprovision_bottles
from ...orchestrator.store.secret_store import ENV_VAR_SECRET_NAME
from ..base import InfraLaunchError
from ..provision_bottle import deprovision_bottle, provision_bottle
from ..util import AGENT_CA_PATH
from . import util as container_mod
@@ -52,10 +53,6 @@ from .gateway_transport import MacosGatewayTransport
from .infra import MacosInfraService, OrchestratorStartError
class ConsolidatedLaunchError(RuntimeError):
"""The consolidated register/provision sequence could not complete."""
@dataclass(frozen=True)
class GatewayEndpoint:
"""What the agent `container run` needs to reach the shared gateway.
@@ -104,13 +101,13 @@ def _push_ca_to_container(name: str, ca_pem: str) -> None:
"""Replace one running agent container's trusted gateway CA with `ca_pem`
and rebuild its trust store via `container cp` + `container exec`.
Unconditional install there is one gateway, so no fingerprint match is
needed. Raises `ConsolidatedLaunchError` on failure."""
needed. Raises `InfraLaunchError` on failure."""
mkdir = container_mod.run_container_argv(
["container", "exec", name, "mkdir", "-p",
"/usr/local/share/ca-certificates"]
)
if mkdir.returncode != 0:
raise ConsolidatedLaunchError(
raise InfraLaunchError(
f"CA push to {name} failed (mkdir): {(mkdir.stderr or '').strip()}"
)
with tempfile.NamedTemporaryFile("w", suffix=".crt") as tmp:
@@ -120,7 +117,7 @@ def _push_ca_to_container(name: str, ca_pem: str) -> None:
["container", "cp", tmp.name, f"{name}:{AGENT_CA_PATH}"]
)
if cp.returncode != 0:
raise ConsolidatedLaunchError(
raise InfraLaunchError(
f"CA push to {name} failed (cp): {(cp.stderr or '').strip()}"
)
ex = container_mod.run_container_argv(
@@ -128,7 +125,7 @@ def _push_ca_to_container(name: str, ca_pem: str) -> None:
f"chmod 644 {AGENT_CA_PATH} && update-ca-certificates"]
)
if ex.returncode != 0:
raise ConsolidatedLaunchError(
raise InfraLaunchError(
f"CA push to {name} failed (update-ca-certificates): "
f"{(ex.stderr or '').strip()}"
)
@@ -154,7 +151,7 @@ def attach_bottled_agents_to_gateway(ca_pem: str | None = None) -> None:
try:
_push_ca_to_container(name, ca_pem)
reconciled += 1
except (OSError, ConsolidatedLaunchError) as exc:
except (OSError, InfraLaunchError) as exc:
info(f"CA reconcile skipped for {name}: {exc}")
if reconciled:
info(f"reconciled gateway CA into {reconciled} running macOS bottle(s)")
@@ -266,7 +263,7 @@ __all__ = [
"live_source_ips",
"register_agent",
"deprovision_consolidated",
"ConsolidatedLaunchError",
"InfraLaunchError",
"OrchestratorStartError",
"GATEWAY_NETWORK",
]
+2 -2
View File
@@ -5,7 +5,7 @@ proxies egress through the one per-host gateway, replacing the per-bottle
companion container removed in #385.
The order differs from docker's, forced by Apple Container 1.0.0 having no
`--ip` (see `consolidated_launch`): the agent is started *before* it is
`--ip` (see `infra_launch`): the agent is started *before* it is
registered, because its DHCP-assigned address — the attribution key — does not
exist until then.
@@ -64,7 +64,7 @@ from . import nested_containers as nested_containers_mod
from .bottle_plan import MacosContainerBottlePlan
from ...orchestrator.store.config_store import resolve_teardown_timeout
from ...orchestrator.store.secret_store import ENV_VAR_SECRET_NAME, new_env_var_secret
from .consolidated_launch import (
from .infra_launch import (
GatewayEndpoint,
ensure_gateway,
register_agent,
+1 -1
View File
@@ -2,7 +2,7 @@
Register a bottle with the orchestrator and provision its git-gate state into
the shared gateway (`provision_bottle`), and the inverse teardown
(`deprovision_bottle`). Backend-neutral — each backend's consolidated_launch
(`deprovision_bottle`). Backend-neutral — each backend's infra_launch
drives these through its own `GatewayTransport` rather than re-implementing
them. The git-gate half of the work lives in `provision_gateway`.
"""