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:
@@ -272,6 +272,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.
|
||||
|
||||
@@ -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()
|
||||
|
||||
+8
-11
@@ -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
|
||||
@@ -85,13 +82,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:
|
||||
@@ -99,7 +96,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(
|
||||
@@ -107,7 +104,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()}"
|
||||
)
|
||||
@@ -143,7 +140,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(
|
||||
@@ -260,5 +257,5 @@ __all__ = [
|
||||
"launch_consolidated",
|
||||
"attach_bottled_agents_to_gateway",
|
||||
"deprovision_consolidated",
|
||||
"ConsolidatedLaunchError",
|
||||
"InfraLaunchError",
|
||||
]
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
+6
-9
@@ -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",
|
||||
]
|
||||
@@ -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:
|
||||
|
||||
+7
-10
@@ -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",
|
||||
]
|
||||
@@ -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,
|
||||
|
||||
@@ -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`.
|
||||
"""
|
||||
|
||||
@@ -55,3 +55,13 @@ agent has two observable states:
|
||||
|
||||
Shorthand for an active (running) Bottled Agent. Used in the supervisor TUI
|
||||
and discovery layer to mean "a bottle whose agent runtime is currently up."
|
||||
|
||||
## Infra
|
||||
|
||||
The per-host pair of shared services every bottle attaches to: the
|
||||
**orchestrator** (control plane — holds the signing key, owns the registry DB,
|
||||
mints tokens) and the **gateway** (data plane — TLS-inspecting egress proxy,
|
||||
git-gate, supervise). Brought up as an idempotent singleton pair by each
|
||||
backend's `InfraService` (two containers on docker/macOS, two microVMs on
|
||||
Firecracker). The per-backend `infra_launch` module composes the bring-up and
|
||||
bottle register/provision sequence against this pair.
|
||||
|
||||
@@ -21,7 +21,7 @@ import subprocess
|
||||
import time
|
||||
import unittest
|
||||
|
||||
from bot_bottle.backend.docker.consolidated_launch import (
|
||||
from bot_bottle.backend.docker.infra_launch import (
|
||||
_network_cidr,
|
||||
_network_container_ips,
|
||||
)
|
||||
|
||||
@@ -11,9 +11,9 @@ from types import SimpleNamespace
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
from bot_bottle.orchestrator.reprovision import reprovision_bottles
|
||||
from bot_bottle.backend.firecracker import consolidated_launch as fc
|
||||
from bot_bottle.backend.macos_container import consolidated_launch as mac
|
||||
from bot_bottle.backend.docker import consolidated_launch as docker
|
||||
from bot_bottle.backend.firecracker import infra_launch as fc
|
||||
from bot_bottle.backend.macos_container import infra_launch as mac
|
||||
from bot_bottle.backend.docker import infra_launch as docker
|
||||
from bot_bottle.orchestrator.client import OrchestratorClientError
|
||||
|
||||
|
||||
@@ -132,7 +132,7 @@ class TestFirecrackerReprovision(unittest.TestCase):
|
||||
def test_persist_failure_is_fatal_to_launch(self) -> None:
|
||||
with patch.object(fc.util, "ssh_base_argv", return_value=["ssh", "guest"]), \
|
||||
patch.object(fc.subprocess, "run", return_value=_proc(1, stderr="denied")):
|
||||
with self.assertRaisesRegex(fc.ConsolidatedLaunchError, "denied"):
|
||||
with self.assertRaisesRegex(fc.InfraLaunchError, "denied"):
|
||||
fc.persist_env_var_secret(Path("/key"), "10.0.0.1", "secret")
|
||||
|
||||
def test_reads_live_vm_key_and_reprovisions(self) -> None:
|
||||
|
||||
@@ -16,7 +16,7 @@ from bot_bottle.agent_provider import AgentProvisionPlan
|
||||
from bot_bottle.backend import BottleSpec
|
||||
from bot_bottle.backend.docker import launch as launch_mod
|
||||
from bot_bottle.backend.docker.bottle_plan import DockerBottlePlan
|
||||
from bot_bottle.backend.docker.consolidated_launch import LaunchContext
|
||||
from bot_bottle.backend.docker.infra_launch import LaunchContext
|
||||
from bot_bottle.egress import EgressPlan
|
||||
from bot_bottle.git_gate import GitGatePlan
|
||||
from bot_bottle.log import Die
|
||||
|
||||
@@ -19,7 +19,7 @@ from bot_bottle.agent_provider import AgentProvisionPlan
|
||||
from bot_bottle.backend import BottleImages, BottleSpec
|
||||
from bot_bottle.backend.docker import launch as launch_mod
|
||||
from bot_bottle.backend.docker.bottle_plan import DockerBottlePlan
|
||||
from bot_bottle.backend.docker.consolidated_launch import LaunchContext
|
||||
from bot_bottle.backend.docker.infra_launch import LaunchContext
|
||||
from bot_bottle.egress import EgressPlan
|
||||
from bot_bottle.git_gate import GitGatePlan
|
||||
from bot_bottle.manifest import ManifestIndex
|
||||
|
||||
@@ -6,8 +6,8 @@ import unittest
|
||||
from pathlib import Path
|
||||
from unittest.mock import MagicMock, Mock, patch
|
||||
|
||||
from bot_bottle.backend.docker.consolidated_launch import (
|
||||
ConsolidatedLaunchError,
|
||||
from bot_bottle.backend.docker.infra_launch import (
|
||||
InfraLaunchError,
|
||||
_network_container_ips,
|
||||
launch_consolidated,
|
||||
deprovision_consolidated,
|
||||
@@ -16,7 +16,7 @@ from bot_bottle.egress import EgressPlan, EgressRoute
|
||||
from bot_bottle.git_gate import GitGatePlan
|
||||
from bot_bottle.orchestrator.client import RegisteredBottle
|
||||
|
||||
_MOD = "bot_bottle.backend.docker.consolidated_launch"
|
||||
_MOD = "bot_bottle.backend.docker.infra_launch"
|
||||
_UTIL = "bot_bottle.backend.provision_bottle"
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ class TestNetworkContainerIps(unittest.TestCase):
|
||||
result = Mock(returncode=1, stdout="", stderr="daemon unavailable")
|
||||
with (
|
||||
patch(f"{_MOD}.run_docker", return_value=result),
|
||||
self.assertRaisesRegex(ConsolidatedLaunchError, "daemon unavailable"),
|
||||
self.assertRaisesRegex(InfraLaunchError, "daemon unavailable"),
|
||||
):
|
||||
_network_container_ips("bot-bottle-gateway")
|
||||
|
||||
@@ -16,7 +16,7 @@ from unittest.mock import ANY, patch
|
||||
|
||||
from bot_bottle.backend.macos_container.bottle import MacosContainerBottle
|
||||
from bot_bottle.backend.macos_container.bottle_plan import MacosContainerBottlePlan
|
||||
from bot_bottle.backend.macos_container.consolidated_launch import GatewayEndpoint
|
||||
from bot_bottle.backend.macos_container.infra_launch import GatewayEndpoint
|
||||
from bot_bottle.backend.macos_container.gateway_hosts import GATEWAY_HOSTNAME
|
||||
from bot_bottle.backend.macos_container.launch import (
|
||||
_agent_run_argv,
|
||||
|
||||
+6
-6
@@ -6,7 +6,7 @@ import unittest
|
||||
from pathlib import Path
|
||||
from unittest.mock import MagicMock, Mock, patch
|
||||
|
||||
from bot_bottle.backend.macos_container.consolidated_launch import (
|
||||
from bot_bottle.backend.macos_container.infra_launch import (
|
||||
GatewayEndpoint,
|
||||
ensure_gateway,
|
||||
register_agent,
|
||||
@@ -16,7 +16,7 @@ from bot_bottle.egress import EgressPlan, EgressRoute
|
||||
from bot_bottle.git_gate import GitGatePlan
|
||||
from bot_bottle.orchestrator.client import RegisteredBottle
|
||||
|
||||
_MOD = "bot_bottle.backend.macos_container.consolidated_launch"
|
||||
_MOD = "bot_bottle.backend.macos_container.infra_launch"
|
||||
_UTIL = "bot_bottle.backend.provision_bottle"
|
||||
|
||||
|
||||
@@ -145,7 +145,7 @@ class TestLiveSourceIps(unittest.TestCase):
|
||||
return [Mock(slug=s) for s in slugs]
|
||||
|
||||
def test_maps_slugs_to_container_addresses(self) -> None:
|
||||
from bot_bottle.backend.macos_container.consolidated_launch import live_source_ips
|
||||
from bot_bottle.backend.macos_container.infra_launch import live_source_ips
|
||||
with patch(f"{_MOD}.enumerate_active", return_value=self._agents("a", "b")), \
|
||||
patch(f"{_MOD}.container_mod.inspect_container_network_ip",
|
||||
side_effect=["10.0.0.1", "10.0.0.2"]) as ip:
|
||||
@@ -156,7 +156,7 @@ class TestLiveSourceIps(unittest.TestCase):
|
||||
def test_containers_without_an_address_are_skipped(self) -> None:
|
||||
"""A container that hasn't been given a DHCP address yet contributes
|
||||
nothing — the reap's grace window, not this list, protects it."""
|
||||
from bot_bottle.backend.macos_container.consolidated_launch import live_source_ips
|
||||
from bot_bottle.backend.macos_container.infra_launch import live_source_ips
|
||||
with patch(f"{_MOD}.enumerate_active", return_value=self._agents("a", "b")), \
|
||||
patch(f"{_MOD}.container_mod.inspect_container_network_ip",
|
||||
side_effect=["", "10.0.0.2"]):
|
||||
@@ -165,7 +165,7 @@ class TestLiveSourceIps(unittest.TestCase):
|
||||
def test_container_list_failure_raises(self) -> None:
|
||||
"""If container list fails, the live set is not authoritative and
|
||||
reconciliation must be skipped."""
|
||||
from bot_bottle.backend.macos_container.consolidated_launch import live_source_ips
|
||||
from bot_bottle.backend.macos_container.infra_launch import live_source_ips
|
||||
from bot_bottle.backend.macos_container.enumerate import EnumerationError
|
||||
with patch(f"{_MOD}.enumerate_active",
|
||||
side_effect=EnumerationError("container list failed")):
|
||||
@@ -174,7 +174,7 @@ class TestLiveSourceIps(unittest.TestCase):
|
||||
|
||||
def test_per_container_inspect_failure_raises(self) -> None:
|
||||
"""If any individual inspect fails, the live set is not authoritative."""
|
||||
from bot_bottle.backend.macos_container.consolidated_launch import live_source_ips
|
||||
from bot_bottle.backend.macos_container.infra_launch import live_source_ips
|
||||
from bot_bottle.backend.macos_container.enumerate import EnumerationError
|
||||
with patch(f"{_MOD}.enumerate_active", return_value=self._agents("a", "b")), \
|
||||
patch(f"{_MOD}.container_mod.inspect_container_network_ip",
|
||||
Reference in New Issue
Block a user