docs: renumber PRD 0081 -> 0083 across the reconcile chunk
test / unit (pull_request) Successful in 1m1s
lint / lint (push) Successful in 1m9s
tracker-policy-pr / check-pr (pull_request) Successful in 14s
test / integration-docker (pull_request) Successful in 1m2s
test / image-input-builds (pull_request) Successful in 56s
test / coverage (pull_request) Successful in 17s
test / unit (pull_request) Successful in 1m1s
lint / lint (push) Successful in 1m9s
tracker-policy-pr / check-pr (pull_request) Successful in 14s
test / integration-docker (pull_request) Successful in 1m2s
test / image-input-builds (pull_request) Successful in 56s
test / coverage (pull_request) Successful in 17s
Follows the base PR's renumber (0081 was already taken; main is on 0082). Update every `PRD 0081` reference in the gateway-attach code, tests, and ADR 0006, plus ADR 0006's link to the PRD file. No behaviour change. Refs #516, #519. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -528,7 +528,7 @@ class BottleBackend(ABC, Generic[PlanT, CleanupT, AttachTargetT]):
|
|||||||
|
|
||||||
def attach_bottled_agents_to_gateway(self) -> None:
|
def attach_bottled_agents_to_gateway(self) -> None:
|
||||||
"""Reconcile every running bottle against the freshly-(re)booted gateway
|
"""Reconcile every running bottle against the freshly-(re)booted gateway
|
||||||
on the cold-boot bring-up path (PRD 0081). The shared flow + fail-hard
|
on the cold-boot bring-up path (PRD 0083). The shared flow + fail-hard
|
||||||
policy live in `gateway_attach`; backends override only the three
|
policy live in `gateway_attach`; backends override only the three
|
||||||
primitives below (ADR 0006)."""
|
primitives below (ADR 0006)."""
|
||||||
from .gateway_attach import reconcile_running_bottles
|
from .gateway_attach import reconcile_running_bottles
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ class DockerBottleBackend(BottleBackend["DockerBottlePlan", "DockerBottleCleanup
|
|||||||
|
|
||||||
def __init__(self, *, infra: "DockerInfraService | None" = None) -> None:
|
def __init__(self, *, infra: "DockerInfraService | None" = None) -> None:
|
||||||
# The infra service whose gateway just cold-booted, passed in on the
|
# The infra service whose gateway just cold-booted, passed in on the
|
||||||
# bring-up reconcile path (PRD 0081) so `_gateway_attach_resources`
|
# bring-up reconcile path (PRD 0083) so `_gateway_attach_resources`
|
||||||
# reads THAT gateway's CA rather than a fresh default-named service —
|
# reads THAT gateway's CA rather than a fresh default-named service —
|
||||||
# otherwise a non-default instance (an isolated integration test's
|
# otherwise a non-default instance (an isolated integration test's
|
||||||
# `-itest-` gateway) reads the default `bot-bottle-orch-gateway`, which
|
# `-itest-` gateway) reads the default `bot-bottle-orch-gateway`, which
|
||||||
|
|||||||
@@ -272,7 +272,7 @@ class DockerGateway(Gateway):
|
|||||||
if self._control_network:
|
if self._control_network:
|
||||||
self._connect_control_network()
|
self._connect_control_network()
|
||||||
# (Re)created a fresh container — signal a cold boot so the caller
|
# (Re)created a fresh container — signal a cold boot so the caller
|
||||||
# reconciles running bottles against it (PRD 0081).
|
# reconciles running bottles against it (PRD 0083).
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _connect_control_network(self) -> None:
|
def _connect_control_network(self) -> None:
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ class DockerInfraService(InfraService):
|
|||||||
)
|
)
|
||||||
# A (re)created gateway container minted/mounted its CA afresh and lost
|
# A (re)created gateway container minted/mounted its CA afresh and lost
|
||||||
# every bottle's per-bottle state; reconcile the already-running bottles
|
# every bottle's per-bottle state; reconcile the already-running bottles
|
||||||
# against it (PRD 0081). Skipped when a healthy current gateway was left
|
# against it (PRD 0083). Skipped when a healthy current gateway was left
|
||||||
# untouched — no cold boot, nothing to reconcile.
|
# untouched — no cold boot, nothing to reconcile.
|
||||||
if cold_booted:
|
if cold_booted:
|
||||||
from .backend import DockerBottleBackend
|
from .backend import DockerBottleBackend
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ def running_agent_containers(
|
|||||||
) -> list[str]:
|
) -> list[str]:
|
||||||
"""Every running agent container on the gateway `network` (the gateway
|
"""Every running agent container on the gateway `network` (the gateway
|
||||||
itself excluded) — the bottles the bring-up reconcile attaches to the fresh
|
itself excluded) — the bottles the bring-up reconcile attaches to the fresh
|
||||||
gateway (PRD 0081). Raises `OSError` if `docker` can't be run (fail hard: a
|
gateway (PRD 0083). Raises `OSError` if `docker` can't be run (fail hard: a
|
||||||
reconcile that can't list its bottles must not look like "no bottles")."""
|
reconcile that can't list its bottles must not look like "no bottles")."""
|
||||||
proc = run_docker([
|
proc = run_docker([
|
||||||
"docker", "network", "inspect", "--format",
|
"docker", "network", "inspect", "--format",
|
||||||
@@ -98,7 +98,7 @@ def running_agent_containers(
|
|||||||
def push_ca_to_container(container: str, ca_pem: str) -> None:
|
def push_ca_to_container(container: str, ca_pem: str) -> None:
|
||||||
"""(Re)attach one running agent container to the current gateway: replace
|
"""(Re)attach one running agent container to the current gateway: replace
|
||||||
its trusted gateway CA with `ca_pem` and rebuild its trust store via
|
its trusted gateway CA with `ca_pem` and rebuild its trust store via
|
||||||
`docker cp` + `docker exec` (PRD 0081). Unconditional install — there is one
|
`docker cp` + `docker exec` (PRD 0083). Unconditional install — there is one
|
||||||
gateway, so no fingerprint match is needed.
|
gateway, so no fingerprint match is needed.
|
||||||
|
|
||||||
Fail hard: raises `InfraLaunchError` (naming the container) on any failure —
|
Fail hard: raises `InfraLaunchError` (naming the container) on any failure —
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ class FirecrackerInfraService(InfraService):
|
|||||||
# The fresh gateway rootfs minted a new CA and lost every bottle's
|
# The fresh gateway rootfs minted a new CA and lost every bottle's
|
||||||
# git-gate/token state; reconcile the already-running bottles against
|
# git-gate/token state; reconcile the already-running bottles against
|
||||||
# it so a gateway rebuild doesn't silently break their egress
|
# it so a gateway rebuild doesn't silently break their egress
|
||||||
# (PRD 0081). Cold-boot only — the adopt fast-paths above never reach
|
# (PRD 0083). Cold-boot only — the adopt fast-paths above never reach
|
||||||
# here, so a healthy current gateway is left untouched.
|
# here, so a healthy current gateway is left untouched.
|
||||||
if cold_booted:
|
if cold_booted:
|
||||||
from .backend import FirecrackerBottleBackend
|
from .backend import FirecrackerBottleBackend
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ def persist_env_var_secret(private_key: Path, guest_ip: str, secret: str) -> Non
|
|||||||
def attach_ca_to_agent_vm(run_dir: Path, ca_pem: str) -> None:
|
def attach_ca_to_agent_vm(run_dir: Path, ca_pem: str) -> None:
|
||||||
"""(Re)attach one running agent VM (identified by its `run_dir`) to the
|
"""(Re)attach one running agent VM (identified by its `run_dir`) to the
|
||||||
current gateway: replace its trusted gateway CA with `ca_pem` and rebuild
|
current gateway: replace its trusted gateway CA with `ca_pem` and rebuild
|
||||||
its trust store over SSH (PRD 0081). Unconditional install — there is one
|
its trust store over SSH (PRD 0083). Unconditional install — there is one
|
||||||
gateway, so no fingerprint match is needed. Bare-pipe input keeps the cert
|
gateway, so no fingerprint match is needed. Bare-pipe input keeps the cert
|
||||||
off argv.
|
off argv.
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
"""The shared gateway-attach reconcile flow (PRD 0081).
|
"""The shared gateway-attach reconcile flow (PRD 0083).
|
||||||
|
|
||||||
`BottleBackend.attach_bottled_agents_to_gateway()` delegates here so every
|
`BottleBackend.attach_bottled_agents_to_gateway()` delegates here so every
|
||||||
backend reconciles running bottles against a freshly-booted gateway *the same
|
backend reconciles running bottles against a freshly-booted gateway *the same
|
||||||
@@ -21,7 +21,7 @@ if TYPE_CHECKING:
|
|||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class GatewayAttachResources:
|
class GatewayAttachResources:
|
||||||
"""Everything a running bottle needs to (re)attach to the current gateway on
|
"""Everything a running bottle needs to (re)attach to the current gateway on
|
||||||
a cold boot (PRD 0081). Gathered once per reconcile and handed to every
|
a cold boot (PRD 0083). Gathered once per reconcile and handed to every
|
||||||
bottle. The CA now; egress secrets and git-gate state join as the reconcile
|
bottle. The CA now; egress secrets and git-gate state join as the reconcile
|
||||||
grows (#516)."""
|
grows (#516)."""
|
||||||
|
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ class MacosGateway(Gateway):
|
|||||||
|
|
||||||
Always returns True: this recreates the gateway container unconditionally
|
Always returns True: this recreates the gateway container unconditionally
|
||||||
(a cold boot), so the caller reconciles running bottles against it
|
(a cold boot), so the caller reconciles running bottles against it
|
||||||
(PRD 0081)."""
|
(PRD 0083)."""
|
||||||
self._orchestrator_url = orchestrator_url
|
self._orchestrator_url = orchestrator_url
|
||||||
self._gateway_token = gateway_token
|
self._gateway_token = gateway_token
|
||||||
# Fail closed on a missing policy source or token: the resolver-only data
|
# Fail closed on a missing policy source or token: the resolver-only data
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ class MacosInfraService(InfraService):
|
|||||||
url, orchestrator.mint_gateway_token())
|
url, orchestrator.mint_gateway_token())
|
||||||
# A (re)created gateway container minted/mounted its CA afresh and lost
|
# A (re)created gateway container minted/mounted its CA afresh and lost
|
||||||
# every bottle's per-bottle state; reconcile the already-running bottles
|
# every bottle's per-bottle state; reconcile the already-running bottles
|
||||||
# against it (PRD 0081). Skipped when a healthy current gateway was left
|
# against it (PRD 0083). Skipped when a healthy current gateway was left
|
||||||
# untouched — no cold boot, nothing to reconcile.
|
# untouched — no cold boot, nothing to reconcile.
|
||||||
if cold_booted:
|
if cold_booted:
|
||||||
from .backend import MacosContainerBottleBackend
|
from .backend import MacosContainerBottleBackend
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ def ensure_gateway(
|
|||||||
|
|
||||||
def running_agent_containers() -> list[str]:
|
def running_agent_containers() -> list[str]:
|
||||||
"""Every running agent container's name — the bottles the bring-up reconcile
|
"""Every running agent container's name — the bottles the bring-up reconcile
|
||||||
attaches to the fresh gateway (PRD 0081). Raises `EnumerationError` if the
|
attaches to the fresh gateway (PRD 0083). Raises `EnumerationError` if the
|
||||||
live set can't be determined (fail hard rather than reconcile a partial
|
live set can't be determined (fail hard rather than reconcile a partial
|
||||||
set)."""
|
set)."""
|
||||||
return [f"{CONTAINER_NAME_PREFIX}{agent.slug}" for agent in enumerate_active()]
|
return [f"{CONTAINER_NAME_PREFIX}{agent.slug}" for agent in enumerate_active()]
|
||||||
@@ -108,7 +108,7 @@ def running_agent_containers() -> list[str]:
|
|||||||
def push_ca_to_container(name: str, ca_pem: str) -> None:
|
def push_ca_to_container(name: str, ca_pem: str) -> None:
|
||||||
"""(Re)attach one running agent container to the current gateway: replace
|
"""(Re)attach one running agent container to the current gateway: replace
|
||||||
its trusted gateway CA with `ca_pem` and rebuild its trust store via
|
its trusted gateway CA with `ca_pem` and rebuild its trust store via
|
||||||
`container cp` + `container exec` (PRD 0081). Unconditional install — there
|
`container cp` + `container exec` (PRD 0083). Unconditional install — there
|
||||||
is one gateway, so no fingerprint match is needed.
|
is one gateway, so no fingerprint match is needed.
|
||||||
|
|
||||||
Fail hard: raises `InfraLaunchError` (naming the container) on any failure —
|
Fail hard: raises `InfraLaunchError` (naming the container) on any failure —
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ class Gateway(abc.ABC):
|
|||||||
so its mitmproxy minted a fresh CA and lost its per-bottle state), False
|
so its mitmproxy minted a fresh CA and lost its per-bottle state), False
|
||||||
when a healthy current gateway was left untouched. The bring-up flow
|
when a healthy current gateway was left untouched. The bring-up flow
|
||||||
uses this as the cold-boot signal that gates the running-bottle
|
uses this as the cold-boot signal that gates the running-bottle
|
||||||
reconcile (`attach_bottled_agents_to_gateway`, PRD 0081)."""
|
reconcile (`attach_bottled_agents_to_gateway`, PRD 0083)."""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def is_running(self) -> bool:
|
def is_running(self) -> bool:
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ macOS-container). Cross-backend operations can be expressed two ways:
|
|||||||
concrete method and each backend overrides small **primitives** it calls.
|
concrete method and each backend overrides small **primitives** it calls.
|
||||||
|
|
||||||
Form 1 gives each backend total freedom, which is exactly the problem: the three
|
Form 1 gives each backend total freedom, which is exactly the problem: the three
|
||||||
implementations drift. The bring-up reconcile (PRD 0081) first shipped as form 1
|
implementations drift. The bring-up reconcile (PRD 0083) first shipped as form 1
|
||||||
and immediately diverged — each backend re-implemented "gather CA → list running
|
and immediately diverged — each backend re-implemented "gather CA → list running
|
||||||
bottles → push to each", and one backend's copy silently skipped failures while
|
bottles → push to each", and one backend's copy silently skipped failures while
|
||||||
another's aborted, an inconsistency caught only in review (#519). The behaviour
|
another's aborted, an inconsistency caught only in review (#519). The behaviour
|
||||||
@@ -37,7 +37,7 @@ method that:
|
|||||||
- delegates only the irreducibly backend-specific steps to `@abstractmethod`
|
- delegates only the irreducibly backend-specific steps to `@abstractmethod`
|
||||||
primitives with narrow, well-typed signatures.
|
primitives with narrow, well-typed signatures.
|
||||||
|
|
||||||
The first application is `attach_bottled_agents_to_gateway()` (PRD 0081): the
|
The first application is `attach_bottled_agents_to_gateway()` (PRD 0083): the
|
||||||
base gathers resources once, attempts every running bottle, and raises an
|
base gathers resources once, attempts every running bottle, and raises an
|
||||||
aggregate `InfraLaunchError` if any failed; backends supply only
|
aggregate `InfraLaunchError` if any failed; backends supply only
|
||||||
`_gateway_attach_resources()`, `_running_bottles()`, and
|
`_gateway_attach_resources()`, `_running_bottles()`, and
|
||||||
@@ -60,6 +60,6 @@ operations whose *shape* should be uniform, not about banning abstract methods.
|
|||||||
|
|
||||||
## Links
|
## Links
|
||||||
|
|
||||||
- PRD 0081 (`docs/prds/0081-reprovision-gateway-state-on-bringup.md`).
|
- PRD 0083 (`docs/prds/0083-reprovision-gateway-state-on-bringup.md`).
|
||||||
- Review that prompted this: PR #519.
|
- Review that prompted this: PR #519.
|
||||||
- `bot_bottle/backend/base.py` (`BottleBackend.attach_bottled_agents_to_gateway`).
|
- `bot_bottle/backend/base.py` (`BottleBackend.attach_bottled_agents_to_gateway`).
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ class TestRuntimeModuleSizes(unittest.TestCase):
|
|||||||
def test_backend_contract_does_not_absorb_preparation_logic(self) -> None:
|
def test_backend_contract_does_not_absorb_preparation_logic(self) -> None:
|
||||||
# base.py holds the backend *contract*; implementation lives elsewhere.
|
# base.py holds the backend *contract*; implementation lives elsewhere.
|
||||||
# The cap is a tripwire against absorbing preparation/impl logic, not a
|
# The cap is a tripwire against absorbing preparation/impl logic, not a
|
||||||
# ban on new contract surface — bumped 580->615 for the PRD 0081
|
# ban on new contract surface — bumped 580->615 for the PRD 0083
|
||||||
# gateway-attach contract (delegator + 3 abstract primitives; the flow
|
# gateway-attach contract (delegator + 3 abstract primitives; the flow
|
||||||
# itself lives in backend/gateway_attach.py, not here).
|
# itself lives in backend/gateway_attach.py, not here).
|
||||||
caps = {
|
caps = {
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ class TestFirecrackerReprovision(unittest.TestCase):
|
|||||||
|
|
||||||
|
|
||||||
class TestAttachFlow(unittest.TestCase):
|
class TestAttachFlow(unittest.TestCase):
|
||||||
"""PRD 0081 / #519 review: the base backend owns the reconcile flow and
|
"""PRD 0083 / #519 review: the base backend owns the reconcile flow and
|
||||||
fails hard — gather resources, attempt every running bottle, then raise an
|
fails hard — gather resources, attempt every running bottle, then raise an
|
||||||
aggregate if any failed (never silently skip)."""
|
aggregate if any failed (never silently skip)."""
|
||||||
|
|
||||||
@@ -208,7 +208,7 @@ class TestAttachFlow(unittest.TestCase):
|
|||||||
|
|
||||||
|
|
||||||
class TestFirecrackerAttachPrimitive(unittest.TestCase):
|
class TestFirecrackerAttachPrimitive(unittest.TestCase):
|
||||||
"""PRD 0081: attach_ca_to_agent_vm pushes the current gateway CA into one
|
"""PRD 0083: attach_ca_to_agent_vm pushes the current gateway CA into one
|
||||||
running agent VM over SSH, failing hard."""
|
running agent VM over SSH, failing hard."""
|
||||||
|
|
||||||
def _run_dir(self, root: Path, ip: str = "10.243.0.3") -> Path:
|
def _run_dir(self, root: Path, ip: str = "10.243.0.3") -> Path:
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ class TestDockerInfraService(unittest.TestCase):
|
|||||||
|
|
||||||
def test_cold_boot_reconciles_running_bottles(self) -> None:
|
def test_cold_boot_reconciles_running_bottles(self) -> None:
|
||||||
# A (re)created gateway (connect returns True) triggers the bring-up
|
# A (re)created gateway (connect returns True) triggers the bring-up
|
||||||
# reconcile so running bottles re-trust the fresh gateway (PRD 0081).
|
# reconcile so running bottles re-trust the fresh gateway (PRD 0083).
|
||||||
self.gw.connect_to_orchestrator.return_value = True
|
self.gw.connect_to_orchestrator.return_value = True
|
||||||
self.svc.ensure_running()
|
self.svc.ensure_running()
|
||||||
self.attach.assert_called_once_with()
|
self.attach.assert_called_once_with()
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ class TestFirecrackerGatewayConnect(unittest.TestCase):
|
|||||||
patch.object(infra_vm, "push_secret") as push:
|
patch.object(infra_vm, "push_secret") as push:
|
||||||
cold_booted = gw.connect_to_orchestrator(_ORCH_URL, _TOKEN)
|
cold_booted = gw.connect_to_orchestrator(_ORCH_URL, _TOKEN)
|
||||||
# The VM is booted fresh here (cold-boot path only), so it always
|
# The VM is booted fresh here (cold-boot path only), so it always
|
||||||
# signals a cold boot → the caller reconciles running bottles (PRD 0081).
|
# signals a cold boot → the caller reconciles running bottles (PRD 0083).
|
||||||
self.assertTrue(cold_booted)
|
self.assertTrue(cold_booted)
|
||||||
# Booted on the gateway link with the gateway role; the orchestrator's
|
# Booted on the gateway link with the gateway role; the orchestrator's
|
||||||
# guest IP (parsed off the URL) rides the cmdline as bb_orch.
|
# guest IP (parsed off the URL) rides the cmdline as bb_orch.
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ _ATTACH = (
|
|||||||
class TestEnsureRunning(unittest.TestCase):
|
class TestEnsureRunning(unittest.TestCase):
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
# The cold-boot branch reconciles running bottles against the fresh
|
# The cold-boot branch reconciles running bottles against the fresh
|
||||||
# gateway (PRD 0081). Stub it so these composition tests stay isolated
|
# gateway (PRD 0083). Stub it so these composition tests stay isolated
|
||||||
# from SSH; the wiring itself is asserted in test_cold_boot_reconciles*.
|
# from SSH; the wiring itself is asserted in test_cold_boot_reconciles*.
|
||||||
ap = patch(_ATTACH)
|
ap = patch(_ATTACH)
|
||||||
self.attach = ap.start()
|
self.attach = ap.start()
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ class TestMacosGatewayConnect(unittest.TestCase):
|
|||||||
|
|
||||||
def test_connect_signals_cold_boot(self) -> None:
|
def test_connect_signals_cold_boot(self) -> None:
|
||||||
# The container is recreated unconditionally, so connect always signals
|
# The container is recreated unconditionally, so connect always signals
|
||||||
# a cold boot → the caller reconciles running bottles (PRD 0081).
|
# a cold boot → the caller reconciles running bottles (PRD 0083).
|
||||||
run = Mock(return_value=_proc())
|
run = Mock(return_value=_proc())
|
||||||
with patch(f"{_GW}.container_mod") as mod, \
|
with patch(f"{_GW}.container_mod") as mod, \
|
||||||
patch(f"{_GW}.host_gateway_ca_dir", return_value=Path("/ca")):
|
patch(f"{_GW}.host_gateway_ca_dir", return_value=Path("/ca")):
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ class TestInfraEnsureRunning(unittest.TestCase):
|
|||||||
|
|
||||||
def test_cold_boot_reconciles_running_bottles(self) -> None:
|
def test_cold_boot_reconciles_running_bottles(self) -> None:
|
||||||
# A (re)created gateway (connect returns True) triggers the bring-up
|
# A (re)created gateway (connect returns True) triggers the bring-up
|
||||||
# reconcile so running bottles re-trust the fresh gateway (PRD 0081).
|
# reconcile so running bottles re-trust the fresh gateway (PRD 0083).
|
||||||
self.gw.connect_to_orchestrator.return_value = True
|
self.gw.connect_to_orchestrator.return_value = True
|
||||||
with patch(f"{_INFRA}.ensure_networks"):
|
with patch(f"{_INFRA}.ensure_networks"):
|
||||||
self.svc.ensure_running()
|
self.svc.ensure_running()
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ class TestDockerGateway(unittest.TestCase):
|
|||||||
self.assertEqual([], [c for c in calls if c[:2] == ["docker", "run"]])
|
self.assertEqual([], [c for c in calls if c[:2] == ["docker", "run"]])
|
||||||
self.assertEqual([], [c for c in calls if c[:2] == ["docker", "rm"]])
|
self.assertEqual([], [c for c in calls if c[:2] == ["docker", "rm"]])
|
||||||
# A healthy current gateway left untouched is not a cold boot — the
|
# A healthy current gateway left untouched is not a cold boot — the
|
||||||
# bring-up flow skips the running-bottle reconcile (PRD 0081).
|
# bring-up flow skips the running-bottle reconcile (PRD 0083).
|
||||||
self.assertFalse(cold_booted)
|
self.assertFalse(cold_booted)
|
||||||
|
|
||||||
def test_ensure_running_recreates_when_image_is_stale(self) -> None:
|
def test_ensure_running_recreates_when_image_is_stale(self) -> None:
|
||||||
@@ -113,7 +113,7 @@ class TestDockerGateway(unittest.TestCase):
|
|||||||
self.assertEqual(1, len([c for c in calls if c[:2] == ["docker", "run"]]))
|
self.assertEqual(1, len([c for c in calls if c[:2] == ["docker", "run"]]))
|
||||||
self.assertTrue(any(c[:2] == ["docker", "rm"] for c in calls))
|
self.assertTrue(any(c[:2] == ["docker", "rm"] for c in calls))
|
||||||
# A recreated container minted/mounted its CA afresh — a cold boot that
|
# A recreated container minted/mounted its CA afresh — a cold boot that
|
||||||
# triggers the running-bottle reconcile (PRD 0081).
|
# triggers the running-bottle reconcile (PRD 0083).
|
||||||
self.assertTrue(cold_booted)
|
self.assertTrue(cold_booted)
|
||||||
|
|
||||||
def test_ensure_running_starts_the_singleton_when_absent(self) -> None:
|
def test_ensure_running_starts_the_singleton_when_absent(self) -> None:
|
||||||
|
|||||||
Reference in New Issue
Block a user