Skip to content

Commit 4d856a5

Browse files
authored
Merge pull request #2 from cucupac/ernesto/fix-managed-runtime-readiness
fix(runtime): skip Docker check for ready database
2 parents e3b0959 + 37a11e0 commit 4d856a5

3 files changed

Lines changed: 75 additions & 7 deletions

File tree

‎app/infrastructure/db/admin/provisioning/docker_prerequisites.py‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,12 @@ def ensure_docker_runtime_available() -> None:
2121
check=False,
2222
)
2323
if completed.returncode != 0:
24+
detail = completed.stderr.strip() or completed.stdout.strip()
25+
if not detail:
26+
detail = f"docker info exited with status {completed.returncode}"
2427
raise InitDependencyError(
25-
"Shellbrain init requires the Docker daemon to be running and reachable."
28+
"Shellbrain requires a reachable Docker daemon for managed-local runtime operations. "
29+
f"docker info failed: {detail}"
2630
)
2731

2832

‎app/startup/runtime_admin.py‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,11 +172,23 @@ def ensure_managed_runtime_ready() -> None:
172172
return
173173
if config.runtime_mode != RUNTIME_MODE_MANAGED_LOCAL:
174174
return
175+
if _postgres_is_ready(config.database.admin_dsn):
176+
return
175177
ensure_managed_runtime_available()
176178
managed_runtime.ensure_existing_managed_container_running(config)
177179
wait_for_postgres(config.database.admin_dsn, timeout_seconds=15)
178180

179181

182+
def _postgres_is_ready(admin_dsn: str) -> bool:
183+
"""Return whether the configured PostgreSQL runtime accepts connections."""
184+
185+
try:
186+
wait_for_postgres(admin_dsn, timeout_seconds=0)
187+
except InitConflictError:
188+
return False
189+
return True
190+
191+
180192
def _build_fresh_machine_config() -> MachineConfig:
181193
"""Construct a fresh machine config for managed-local mode."""
182194

‎tests/operations/recovery/execution/test_init_bootstrap.py‎

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22

33
from __future__ import annotations
44

5+
import subprocess
56
from contextlib import nullcontext
67
from pathlib import Path
78

89
import pytest
910

1011
import app.startup.runtime_admin as init_module
12+
from app.core.entities.admin_errors import InitConflictError, InitDependencyError
1113
from app.core.entities.machine_config import (
1214
BackupState,
1315
DatabaseState,
@@ -16,6 +18,7 @@
1618
ManagedInstanceState,
1719
)
1820
from app.infrastructure.db.admin.provisioning import managed_local as managed_runtime
21+
from app.infrastructure.db.admin.provisioning import docker_prerequisites
1922
from app.infrastructure.local_state.repo_registration_store import RepoRegistration
2023
from app.entrypoints.cli.presenters.init import render_success_lines as render_init_lines
2124

@@ -691,7 +694,32 @@ def test_external_init_should_skip_managed_container_setup(
691694
assert saved[0].runtime_mode == "external_postgres"
692695

693696

694-
def test_ensure_managed_runtime_ready_should_start_managed_container_and_wait(
697+
def test_ensure_managed_runtime_ready_should_skip_docker_when_postgres_is_ready(
698+
monkeypatch,
699+
) -> None:
700+
"""operation readiness should use an available configured database directly."""
701+
702+
config = _machine_config(bootstrap_state="ready")
703+
calls: list[object] = []
704+
705+
monkeypatch.setattr(init_module, "try_load_machine_config", lambda: (config, None))
706+
monkeypatch.setattr(
707+
init_module,
708+
"ensure_managed_runtime_available",
709+
lambda: (_ for _ in ()).throw(AssertionError("unexpected docker check")),
710+
)
711+
monkeypatch.setattr(
712+
init_module,
713+
"wait_for_postgres",
714+
lambda dsn, timeout_seconds: calls.append((dsn, timeout_seconds)),
715+
)
716+
717+
init_module.ensure_managed_runtime_ready()
718+
719+
assert calls == [(config.database.admin_dsn, 0)]
720+
721+
722+
def test_ensure_managed_runtime_ready_should_start_unavailable_managed_container(
695723
monkeypatch,
696724
) -> None:
697725
"""operation readiness should start the configured managed runtime once."""
@@ -708,21 +736,45 @@ def test_ensure_managed_runtime_ready_should_start_managed_container_and_wait(
708736
"ensure_existing_managed_container_running",
709737
lambda received: calls.append(("container", received)) or True,
710738
)
711-
monkeypatch.setattr(
712-
init_module,
713-
"wait_for_postgres",
714-
lambda dsn, timeout_seconds: calls.append(("wait", dsn, timeout_seconds)),
715-
)
739+
740+
def wait(dsn: str, timeout_seconds: int) -> None:
741+
calls.append(("wait", dsn, timeout_seconds))
742+
if timeout_seconds == 0:
743+
raise InitConflictError("not ready")
744+
745+
monkeypatch.setattr(init_module, "wait_for_postgres", wait)
716746

717747
init_module.ensure_managed_runtime_ready()
718748

719749
assert calls == [
750+
("wait", config.database.admin_dsn, 0),
720751
"deps",
721752
("container", config),
722753
("wait", config.database.admin_dsn, 15),
723754
]
724755

725756

757+
def test_docker_readiness_error_should_include_docker_detail(monkeypatch) -> None:
758+
"""docker readiness should preserve the failure reported by Docker."""
759+
760+
monkeypatch.setattr(
761+
docker_prerequisites.shutil, "which", lambda name: "/usr/bin/docker"
762+
)
763+
monkeypatch.setattr(
764+
docker_prerequisites.subprocess,
765+
"run",
766+
lambda *args, **kwargs: subprocess.CompletedProcess(
767+
args=["docker", "info"],
768+
returncode=1,
769+
stdout="",
770+
stderr="permission denied while connecting to the Docker socket",
771+
),
772+
)
773+
774+
with pytest.raises(InitDependencyError, match="permission denied"):
775+
docker_prerequisites.ensure_docker_runtime_available()
776+
777+
726778
@pytest.mark.parametrize(
727779
"loaded_factory",
728780
[

0 commit comments

Comments
 (0)