mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-08 11:46:35 +00:00
fix(swarm-test): ask the swarm for the DB service
03_wait_converge built the DB service name from the engine type:
"${DB_DEP}_${DB_DEP}" -> mariadb_mariadb. That name is only correct when
the database is central. force_shared_db deliberately leaves a
manager-pinned role carrying a literal `shared: false` alone, so
web-app-magento keeps its embedded engine, and sys-svc-rdbms deploys it as
magento_database inside magento's own stack.
The name came from the engine, which is global, and was looked up with
`docker service ls` across the whole swarm instead of the role's stack, so
the `shared` flag never entered the check at any step. Both polarities were
wrong:
variant #1 - no consumer pulls the central provider in, so
mariadb_mariadb does not exist. Run 32630684501 job 97175522113 polled it
ninety times and failed the drill, while the rescue artifact shows
magento_database at 1/1 Running and the play at failed=0.
variant #0 - matomo and mailu declare a Jinja `shared`, get force-shared
and drag svc-db-mariadb in. Job 95662862942 then reported
`db(mariadb): 1/1 Running 2 hours ago` beside `magento: Running 21
minutes ago` - green on a database magento never touches.
resolve_db_service asks the deployed swarm which service carries this
role's database: <entity>_database first, else <dep>_<dep>. The two cannot
collide, because sys-svc-rdbms renders the _database sidecar only under
`lookup('database', application_id, 'local')`. Exact-line matching, not
docker's substring name filter, per 246558a13.
Only web-app-magento changes behaviour: it is the one role that is both
pinned by force_shared_db and seen by the DB_DEP grep. matrix and
bigbluebutton never reach the DB half - their entity key carries no image,
so skip_if_no_swarm_service exits first - and discourse resolves
postgres_postgres exactly as before, in every variant.
A role that declares a DB dep no service serves now says so and gates the
app half alone, instead of polling a name nobody deployed.
diagnostics.sh carried the same guess in its container filter.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
73ae405854
commit
8230c187a2
4 files changed
+119
-10
No files matched your search
@@ -0,0 +1,92 @@
|
||||
"""Which swarm service the converge gate accepts as a role's database.
|
||||
|
||||
``resolve_db_service`` in ``scripts/tests/deploy/swarm/utils/_context.sh`` picks
|
||||
between two naming schemes that ``plugins/lookup/database.py`` keeps apart: a
|
||||
role pinning its own engine runs it as ``<entity>_database`` inside its own
|
||||
stack, a central provider as ``<dep>_<dep>`` in its own. Guessing one of them
|
||||
cost run 32630684501 a job - ``mariadb_mariadb`` never existed for Magento - and
|
||||
the same guess passed vacuously in the all-bonds variant, where an unrelated
|
||||
role had dragged the central provider in. Pinned here: the local engine wins
|
||||
when both are deployed, the central name is still used when only it exists, and
|
||||
a name that is deployed for nobody yields nothing instead of a false match.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
from utils.cache.files import PROJECT_ROOT
|
||||
|
||||
CONTEXT = (
|
||||
PROJECT_ROOT / "scripts" / "tests" / "deploy" / "swarm" / "utils" / "_context.sh"
|
||||
)
|
||||
PINNED_ENGINE_APP = "web-app-magento"
|
||||
NO_DB_APP = "web-svc-html"
|
||||
LOCAL_SERVICE = "magento_database"
|
||||
CENTRAL_SERVICE = "mariadb_mariadb"
|
||||
|
||||
|
||||
class TestResolveDbService(unittest.TestCase):
|
||||
def _resolve(self, app_id: str, deployed: tuple[str, ...]) -> str:
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
stub_bin = Path(tmp) / "bin"
|
||||
stub_bin.mkdir()
|
||||
docker = stub_bin / "docker"
|
||||
docker.write_text(
|
||||
"#!/usr/bin/env bash\nprintf '%s\\n' {}\n".format(
|
||||
" ".join(f"'{name}'" for name in deployed) or '""'
|
||||
)
|
||||
)
|
||||
docker.chmod(0o755)
|
||||
|
||||
env = dict(os.environ)
|
||||
env.update(
|
||||
APP_ID=app_id,
|
||||
MGR="stub-manager",
|
||||
PATH=f"{stub_bin}:{env['PATH']}",
|
||||
BASH_ENV="",
|
||||
)
|
||||
proc = subprocess.run(
|
||||
["bash", "-c", f'source "{CONTEXT}"; resolve_db_service'],
|
||||
cwd=PROJECT_ROOT,
|
||||
env=env,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True,
|
||||
)
|
||||
return proc.stdout.strip()
|
||||
|
||||
def test_the_local_engine_wins_when_the_central_one_is_also_deployed(self) -> None:
|
||||
self.assertEqual(
|
||||
self._resolve(PINNED_ENGINE_APP, (LOCAL_SERVICE, CENTRAL_SERVICE)),
|
||||
LOCAL_SERVICE,
|
||||
)
|
||||
|
||||
def test_the_local_engine_is_found_when_it_is_the_only_one(self) -> None:
|
||||
self.assertEqual(
|
||||
self._resolve(PINNED_ENGINE_APP, (LOCAL_SERVICE,)), LOCAL_SERVICE
|
||||
)
|
||||
|
||||
def test_the_central_provider_is_used_when_no_local_engine_exists(self) -> None:
|
||||
self.assertEqual(
|
||||
self._resolve(PINNED_ENGINE_APP, (CENTRAL_SERVICE,)), CENTRAL_SERVICE
|
||||
)
|
||||
|
||||
def test_a_substring_of_a_deployed_name_is_not_a_match(self) -> None:
|
||||
self.assertEqual(
|
||||
self._resolve(PINNED_ENGINE_APP, ("other_mariadb_mariadb_replica",)), ""
|
||||
)
|
||||
|
||||
def test_nothing_is_resolved_when_neither_scheme_is_deployed(self) -> None:
|
||||
self.assertEqual(self._resolve(PINNED_ENGINE_APP, ("magento_nginx",)), "")
|
||||
|
||||
def test_a_role_without_a_database_dep_resolves_nothing(self) -> None:
|
||||
self.assertEqual(self._resolve(NO_DB_APP, (CENTRAL_SERVICE,)), "")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user