Public Access
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6053fb9fba | ||
|
|
e76741bfad |
@@ -2,6 +2,12 @@
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [0.9.1] - 2026-06-23
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Always start dockerd in CI runner for molecule tests
|
||||
|
||||
## [0.9.0] - 2026-06-23
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
"""devx — reusable development and CI/CD tools for oblachno-oss projects."""
|
||||
|
||||
__version__ = "0.9.0"
|
||||
__version__ = "0.9.1"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Start a Docker daemon inside a CI runner container (Docker-in-Docker).
|
||||
|
||||
CI runners (e.g. ``gitea/runner-images:ubuntu-latest``) may not have a
|
||||
Docker daemon running. This module starts ``dockerd`` in the background
|
||||
and waits for it to become ready, or exits immediately if Docker is
|
||||
already available.
|
||||
CI runners (e.g. ``gitea/runner-images:ubuntu-latest``) may have the host's
|
||||
Docker socket mounted, but molecule needs a local Docker daemon to create
|
||||
nested containers. This module always starts ``dockerd`` in the background
|
||||
and waits for it to become ready.
|
||||
|
||||
Usage::
|
||||
|
||||
@@ -38,14 +38,13 @@ def is_docker_ready() -> bool:
|
||||
def start_docker_daemon(timeout: int = DEFAULT_TIMEOUT) -> bool:
|
||||
"""Start dockerd in the background and wait for it to be ready.
|
||||
|
||||
Returns ``True`` if Docker is ready (either already running or
|
||||
successfully started), ``False`` if it failed to start within
|
||||
the timeout.
|
||||
"""
|
||||
if is_docker_ready():
|
||||
click.echo(_("Docker daemon already running"))
|
||||
return True
|
||||
Always starts a local dockerd even if ``docker info`` succeeds,
|
||||
because the host socket may be mounted but not suitable for
|
||||
molecule's nested container creation.
|
||||
|
||||
Returns ``True`` if Docker is ready, ``False`` if it failed to
|
||||
start within the timeout.
|
||||
"""
|
||||
click.echo(_("Starting Docker daemon..."))
|
||||
log_file = open(DOCKERD_LOG, "w") # noqa: SIM115
|
||||
subprocess.Popen( # nosec B603 B607
|
||||
|
||||
@@ -419,13 +419,6 @@
|
||||
"ru": "Created release commit.",
|
||||
"zh": "Created release commit."
|
||||
},
|
||||
"Docker daemon already running": {
|
||||
"bg": "Docker daemon already running",
|
||||
"de": "Docker-Daemon läuft bereits",
|
||||
"en": "Docker daemon already running",
|
||||
"ru": "Docker-демон уже запущен",
|
||||
"zh": "Docker 守护进程已在运行"
|
||||
},
|
||||
"Docker daemon failed to start": {
|
||||
"bg": "Docker daemon failed to start",
|
||||
"de": "Docker-Daemon konnte nicht gestartet werden",
|
||||
|
||||
@@ -21,11 +21,6 @@ class TestIsDockerReady:
|
||||
|
||||
|
||||
class TestStartDockerDaemon:
|
||||
@patch("devx.molecule.start_docker.is_docker_ready", return_value=True)
|
||||
def test_already_running(self, mock_ready: MagicMock) -> None:
|
||||
assert start_docker_daemon() is True
|
||||
mock_ready.assert_called_once()
|
||||
|
||||
@patch("devx.molecule.start_docker.time.sleep")
|
||||
@patch("devx.molecule.start_docker.is_docker_ready")
|
||||
@patch("devx.molecule.start_docker.subprocess.Popen")
|
||||
@@ -37,11 +32,11 @@ class TestStartDockerDaemon:
|
||||
mock_ready: MagicMock,
|
||||
mock_sleep: MagicMock,
|
||||
) -> None:
|
||||
# First call: initial check (not ready). Second: first loop iteration (ready).
|
||||
# First loop iteration: dockerd not ready yet. Second: ready.
|
||||
mock_ready.side_effect = [False, True]
|
||||
assert start_docker_daemon(timeout=5) is True
|
||||
mock_popen.assert_called_once()
|
||||
mock_sleep.assert_not_called()
|
||||
mock_sleep.assert_called_once_with(1)
|
||||
|
||||
@patch("devx.molecule.start_docker.time.sleep")
|
||||
@patch("devx.molecule.start_docker.is_docker_ready", return_value=False)
|
||||
@@ -54,11 +49,26 @@ class TestStartDockerDaemon:
|
||||
mock_ready: MagicMock,
|
||||
mock_sleep: MagicMock,
|
||||
) -> None:
|
||||
# is_docker_ready always returns False: 1 initial + 3 loop iterations = 4 calls
|
||||
assert start_docker_daemon(timeout=3) is False
|
||||
mock_popen.assert_called_once()
|
||||
assert mock_sleep.call_count == 3
|
||||
|
||||
@patch("devx.molecule.start_docker.time.sleep")
|
||||
@patch("devx.molecule.start_docker.is_docker_ready")
|
||||
@patch("devx.molecule.start_docker.subprocess.Popen")
|
||||
@patch("builtins.open", new_callable=mock_open)
|
||||
def test_ready_on_first_check(
|
||||
self,
|
||||
mock_file: MagicMock,
|
||||
mock_popen: MagicMock,
|
||||
mock_ready: MagicMock,
|
||||
mock_sleep: MagicMock,
|
||||
) -> None:
|
||||
mock_ready.return_value = True
|
||||
assert start_docker_daemon(timeout=5) is True
|
||||
mock_popen.assert_called_once()
|
||||
mock_sleep.assert_not_called()
|
||||
|
||||
@patch("devx.molecule.start_docker.time.sleep")
|
||||
@patch("devx.molecule.start_docker.is_docker_ready")
|
||||
@patch("devx.molecule.start_docker.subprocess.Popen")
|
||||
@@ -70,9 +80,8 @@ class TestStartDockerDaemon:
|
||||
mock_ready: MagicMock,
|
||||
mock_sleep: MagicMock,
|
||||
) -> None:
|
||||
# First call: initial check (not ready). Then 9 loop iterations (not ready),
|
||||
# 10th iteration (ready).
|
||||
mock_ready.side_effect = [False] * 10 + [True]
|
||||
# 9 iterations not ready, 10th ready.
|
||||
mock_ready.side_effect = [False] * 9 + [True]
|
||||
assert start_docker_daemon(timeout=10) is True
|
||||
assert mock_sleep.call_count == 9
|
||||
|
||||
|
||||
Reference in New Issue
Block a user