mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-08 11:46:35 +00:00
Twelve files conflicted; most resolutions keep both sides rather than pick
one.
cli env.py and compose.py: both branches extend the same spots. The tools
override is appended before write_override, because that call filters the
mirror override to the compose files it is handed. compose.py keeps this
branch's CACHE_ROLE_SHELL_DIR, since the cache scripts moved into a role and
main's literal scripts/docker/cache path is their old home, and takes main's
mirrored init image alongside it.
utils/docker/image/discovery.py: this branch's version_variants expansion
plus main's whole runner-image block, which runner_mirror imports.
sys-svc-compose network create: main's side wins on substance and this
branch's on structure. main carries eda6249d7b, the fix for a probe that
matched an id prefix and let a sibling shadow the exact name; this branch had
refactored the task into create/overlay.yml and create/bridge.yml but brought
back the docker_network_info probe that fix replaced. The subfiles stay and
now probe through the exact-name lookup. main's half also read
SWARM_CLUSTER_AVAILABLE, which this branch removed in favour of
IS_SWARM_MODE, as the merge base confirms, so the gates follow this branch.
The lookup's import follows this branch's get_entity_name to entity_name
rename.
web-app-pixelfed: the custom entrypoints stay removed, since the new image
brings its own and the variables behind them no longer exist, and main's
host_alias=true comes along.
web-app-suitecrm: main's session.yaml and its config/packages path, because
only that version wires framework.session and only that directory is read by
Symfony.
web-app-odoo: main's onionOptions import is required by the test.use below
it; this branch's test-seaweedfs registration stays.
Four defects surfaced that no conflict marker shows.
The auto-merge of web-app-suitecrm/vars/main.yml duplicated
SUITECRM_SESSION_CONFIG_HOST, which ansible-lint rejects. Removing it exposed
the second: SUITECRM_SESSION_CONFIG_DOCKER still named config/session.yaml
while the mount had moved to config/packages, so the freshness comparison in
tasks/01_manager_ops.yml would have tested a path nothing writes.
svc-db-elasticsearch carried environment: on two include_tasks, which Ansible
accepts on include_role only. ELASTIC_PW now sits on the five tasks that read
it, which is also the tighter scope for a credential.
The openclaw templates render NETWORK_TRUSTED_PROXY_CIDRS while their test
renderer passes only its explicit kwargs, so seven tests raised Undefined.
That predates the merge: the template line is on this branch and not on main,
and both sides share the same test file.
test_runner_mirror neutralises four environment variables under clear=False
and missed three, so the gpu and tools overrides leaked in from the container
and the assertion on the layered list broke. It now neutralises all seven.
make quality-high passes both phases.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
342 lines
11 KiB
Python
342 lines
11 KiB
Python
# tests/cli/administration/deploy/development/test_compose.py
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import subprocess
|
|
import unittest
|
|
from pathlib import Path
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
from cli.administration.deploy.development.compose import Compose
|
|
|
|
|
|
class TestComposeUpRetries(unittest.TestCase):
|
|
def _compose(self) -> Compose:
|
|
return Compose(repo_root=Path("/tmp/infinito-nexus"), distro="arch")
|
|
|
|
@patch("time.sleep", autospec=True)
|
|
def test_compose_up_with_retries_succeeds_after_transient_failures(
|
|
self, sleep_mock: MagicMock
|
|
) -> None:
|
|
compose = self._compose()
|
|
|
|
compose.run = MagicMock(
|
|
side_effect=[
|
|
subprocess.CalledProcessError(1, ["docker", "compose"], "out1", "err1"),
|
|
subprocess.CalledProcessError(1, ["docker", "compose"], "out2", "err2"),
|
|
subprocess.CompletedProcess(
|
|
["docker", "compose"], 0, stdout="", stderr=""
|
|
),
|
|
]
|
|
)
|
|
|
|
args = [
|
|
"up",
|
|
"-d",
|
|
"--no-build",
|
|
"coredns",
|
|
"infinito",
|
|
]
|
|
compose._compose_up_with_retries(args, attempts=6, delay_s=30)
|
|
|
|
self.assertEqual(compose.run.call_count, 3)
|
|
|
|
self.assertEqual(sleep_mock.call_count, 2)
|
|
sleep_mock.assert_any_call(30)
|
|
self.assertTrue(all(call.args == (30,) for call in sleep_mock.call_args_list))
|
|
|
|
@patch("time.sleep", autospec=True)
|
|
def test_compose_up_with_retries_raises_after_exhausting_attempts(
|
|
self, sleep_mock: MagicMock
|
|
) -> None:
|
|
compose = self._compose()
|
|
|
|
compose.run = MagicMock(
|
|
side_effect=subprocess.CalledProcessError(
|
|
1, ["docker", "compose"], "out", "err"
|
|
)
|
|
)
|
|
|
|
args = ["up", "-d", "coredns", "infinito"]
|
|
|
|
with self.assertRaises(subprocess.CalledProcessError):
|
|
compose._compose_up_with_retries(args, attempts=6, delay_s=30)
|
|
|
|
self.assertEqual(compose.run.call_count, 6)
|
|
|
|
self.assertEqual(sleep_mock.call_count, 5)
|
|
self.assertTrue(all(call.args == (30,) for call in sleep_mock.call_args_list))
|
|
|
|
@patch("time.sleep", autospec=True)
|
|
def test_compose_up_with_retries_no_sleep_if_first_try_succeeds(
|
|
self, sleep_mock: MagicMock
|
|
) -> None:
|
|
compose = self._compose()
|
|
|
|
compose.run = MagicMock(
|
|
return_value=subprocess.CompletedProcess(
|
|
["docker", "compose"], 0, stdout="", stderr=""
|
|
)
|
|
)
|
|
|
|
args = ["up", "-d", "coredns", "infinito"]
|
|
compose._compose_up_with_retries(args, attempts=6, delay_s=30)
|
|
|
|
self.assertEqual(compose.run.call_count, 1)
|
|
sleep_mock.assert_not_called()
|
|
|
|
@patch.dict(
|
|
os.environ,
|
|
{
|
|
"INFINITO_IMAGE": "test-image/arch",
|
|
"GITHUB_ACTIONS": "true",
|
|
"INFINITO_RUNNING_ON_GITHUB": "true",
|
|
"CI": "true",
|
|
"INFINITO_GIT_COMMON_DIR": "",
|
|
"INFINITO_CACHE_NETWORK": "",
|
|
"INFINITO_CACHE_STACK": "",
|
|
"INFINITO_GPU_COUNT": "0",
|
|
},
|
|
clear=False,
|
|
)
|
|
@patch(
|
|
"cli.administration.deploy.development.runner_mirror.write_override",
|
|
return_value="build/compose/runner-mirror.override.yml",
|
|
)
|
|
@patch("subprocess.run", autospec=True)
|
|
def test_run_skips_cache_override_on_github_runner(
|
|
self, run_mock: MagicMock, _write_override: MagicMock
|
|
) -> None:
|
|
compose = self._compose()
|
|
|
|
run_mock.return_value = subprocess.CompletedProcess(
|
|
["docker", "compose", "ps", "-q", "infinito"],
|
|
0,
|
|
stdout="cid\n",
|
|
stderr="",
|
|
)
|
|
|
|
r = compose.run(["ps", "-q", "infinito"], check=False, capture=True)
|
|
|
|
self.assertEqual(r.returncode, 0)
|
|
self.assertEqual(run_mock.call_count, 1)
|
|
|
|
cmd = run_mock.call_args.args[0]
|
|
env = run_mock.call_args.kwargs["env"]
|
|
|
|
self.assertEqual(
|
|
cmd,
|
|
[
|
|
"docker",
|
|
"compose",
|
|
"-f",
|
|
"compose.yml",
|
|
"-f",
|
|
"compose/tools.override.yml",
|
|
"-f",
|
|
"build/compose/runner-mirror.override.yml",
|
|
"ps",
|
|
"-q",
|
|
"infinito",
|
|
],
|
|
)
|
|
self.assertEqual(env["INFINITO_DISTRO"], "arch")
|
|
self.assertNotIn("COMPOSE_PROFILES", env)
|
|
|
|
@patch.dict(
|
|
os.environ,
|
|
{
|
|
"INFINITO_IMAGE": "test-image/arch",
|
|
"GITHUB_ACTIONS": "",
|
|
"INFINITO_RUNNING_ON_GITHUB": "",
|
|
"CI": "",
|
|
"INFINITO_GIT_COMMON_DIR": "",
|
|
"INFINITO_CACHE_NETWORK": "",
|
|
"INFINITO_CACHE_STACK": "",
|
|
"INFINITO_GPU_COUNT": "0",
|
|
},
|
|
clear=False,
|
|
)
|
|
@patch("subprocess.run", autospec=True)
|
|
def test_run_layers_cache_override_locally(self, run_mock: MagicMock) -> None:
|
|
compose = self._compose()
|
|
|
|
run_mock.return_value = subprocess.CompletedProcess(
|
|
["docker", "compose"], 0, stdout="", stderr=""
|
|
)
|
|
|
|
compose.run(["ps", "-q", "infinito"], check=False, capture=True)
|
|
|
|
cmd = run_mock.call_args.args[0]
|
|
env = run_mock.call_args.kwargs["env"]
|
|
|
|
self.assertEqual(
|
|
cmd,
|
|
[
|
|
"docker",
|
|
"compose",
|
|
"-f",
|
|
"compose.yml",
|
|
"-f",
|
|
"compose/cache.override.yml",
|
|
"-f",
|
|
"compose/tools.override.yml",
|
|
"ps",
|
|
"-q",
|
|
"infinito",
|
|
],
|
|
)
|
|
self.assertEqual(
|
|
env["INFINITO_CACHE_REGISTRY_PROXY_CONF"], # nocheck: test-fixture
|
|
"./compose/registry-cache/proxy.conf",
|
|
)
|
|
self.assertTrue(
|
|
env["INFINITO_CACHE_PACKAGE_FRONTEND_CA_FILE"].endswith(
|
|
"/ca.crt"
|
|
) # nocheck: test-fixture
|
|
)
|
|
|
|
@patch.dict(
|
|
os.environ,
|
|
{
|
|
"INFINITO_BUILD": "1",
|
|
"INFINITO_IMAGE": "infinito-debian",
|
|
"INFINITO_PULL_POLICY": "never",
|
|
"CI": "true",
|
|
"GITHUB_ACTIONS": "true",
|
|
"INFINITO_RUNNING_ON_GITHUB": "true",
|
|
"INFINITO_CACHE_STACK": "",
|
|
},
|
|
clear=False,
|
|
)
|
|
def test_up_builds_when_build_flag_is_enabled(self) -> None:
|
|
compose = self._compose()
|
|
compose._render_coredns_corefile = MagicMock()
|
|
compose._compose_up_with_retries = MagicMock()
|
|
compose.wait_for_healthy = MagicMock()
|
|
|
|
compose.up(run_entry_init=False)
|
|
|
|
compose._compose_up_with_retries.assert_called_once_with(
|
|
["up", "-d", "coredns", "infinito"],
|
|
attempts=6,
|
|
delay_s=30,
|
|
)
|
|
compose.wait_for_healthy.assert_called_once_with()
|
|
|
|
@patch.dict(
|
|
os.environ,
|
|
{
|
|
"INFINITO_BUILD": "0",
|
|
"INFINITO_IMAGE": "test-image/arch",
|
|
"CI": "true",
|
|
"GITHUB_ACTIONS": "true",
|
|
"INFINITO_RUNNING_ON_GITHUB": "true",
|
|
"INFINITO_CACHE_STACK": "",
|
|
},
|
|
clear=False,
|
|
)
|
|
def test_up_skips_build_when_build_flag_is_disabled(self) -> None:
|
|
compose = self._compose()
|
|
compose._render_coredns_corefile = MagicMock()
|
|
compose._compose_up_with_retries = MagicMock()
|
|
compose.wait_for_healthy = MagicMock()
|
|
|
|
compose.up(run_entry_init=False)
|
|
|
|
compose._compose_up_with_retries.assert_called_once_with(
|
|
[
|
|
"up",
|
|
"-d",
|
|
"--no-build",
|
|
"coredns",
|
|
"infinito",
|
|
],
|
|
attempts=6,
|
|
delay_s=30,
|
|
)
|
|
compose.wait_for_healthy.assert_called_once_with()
|
|
|
|
@patch.dict(
|
|
os.environ,
|
|
{
|
|
"INFINITO_BUILD": "1",
|
|
"INFINITO_IMAGE": "infinito-debian",
|
|
"INFINITO_PULL_POLICY": "never",
|
|
"CI": "",
|
|
"GITHUB_ACTIONS": "",
|
|
"INFINITO_RUNNING_ON_GITHUB": "",
|
|
"INFINITO_GIT_COMMON_DIR": "",
|
|
"INFINITO_CACHE_NETWORK": "",
|
|
"INFINITO_CACHE_STACK": "",
|
|
},
|
|
clear=False,
|
|
)
|
|
def test_up_includes_cache_services_when_local(self) -> None:
|
|
compose = self._compose()
|
|
compose._render_coredns_corefile = MagicMock()
|
|
compose._compose_up_with_retries = MagicMock()
|
|
compose.wait_for_healthy = MagicMock()
|
|
compose._bootstrap_package_cache = MagicMock()
|
|
compose._generate_package_frontend_certs = MagicMock()
|
|
compose._install_package_frontend_ca_in_runner = MagicMock()
|
|
|
|
compose.up(run_entry_init=False)
|
|
|
|
compose._compose_up_with_retries.assert_called_once_with(
|
|
[
|
|
"up",
|
|
"-d",
|
|
"registry-cache",
|
|
"package-cache",
|
|
"package-cache-frontend",
|
|
"coredns",
|
|
"infinito",
|
|
],
|
|
attempts=6,
|
|
delay_s=30,
|
|
)
|
|
compose.wait_for_healthy.assert_called_once_with()
|
|
compose._bootstrap_package_cache.assert_called_once()
|
|
compose._generate_package_frontend_certs.assert_called_once()
|
|
compose._install_package_frontend_ca_in_runner.assert_called_once()
|
|
|
|
@patch.dict(
|
|
os.environ,
|
|
{
|
|
"INFINITO_BUILD": "1",
|
|
"INFINITO_IMAGE": "infinito-debian",
|
|
"INFINITO_PULL_POLICY": "never",
|
|
"CI": "",
|
|
"GITHUB_ACTIONS": "",
|
|
"INFINITO_RUNNING_ON_GITHUB": "",
|
|
"INFINITO_GIT_COMMON_DIR": "/primary/.git",
|
|
"INFINITO_CACHE_NETWORK": "infinito-nexus-core_default",
|
|
"INFINITO_CACHE_STACK": "",
|
|
},
|
|
clear=False,
|
|
)
|
|
def test_up_applies_the_declarations_to_a_cache_stack_it_shares(self) -> None:
|
|
compose = self._compose()
|
|
compose._render_coredns_corefile = MagicMock()
|
|
compose._compose_up_with_retries = MagicMock()
|
|
compose.wait_for_healthy = MagicMock()
|
|
compose._bootstrap_package_cache = MagicMock()
|
|
compose._generate_package_frontend_certs = MagicMock()
|
|
compose._apply_shared_cache = MagicMock()
|
|
compose._install_package_frontend_ca_in_runner = MagicMock()
|
|
|
|
compose.up(run_entry_init=False)
|
|
|
|
compose._compose_up_with_retries.assert_called_once_with(
|
|
["up", "-d", "coredns", "infinito"], attempts=6, delay_s=30
|
|
)
|
|
compose._generate_package_frontend_certs.assert_not_called()
|
|
compose._bootstrap_package_cache.assert_not_called()
|
|
compose._apply_shared_cache.assert_called_once()
|
|
compose._install_package_frontend_ca_in_runner.assert_called_once()
|
|
|
|
|
|
if __name__ == "__main__": # pragma: no cover
|
|
unittest.main()
|