mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 10:59:59 +00:00
refactor(meta): split database PORT_BAND into mariadb + postgres + disjoint lint
The single `local.database` PORT_BAND covered both 3306 (MariaDB)
and 5432 (PostgreSQL), which let any port in 3306-5432 pass band
membership without distinguishing the engine. Replace with two
explicit single-port bands so the (scope, category) tuple
identifies the engine unambiguously:
- group_vars/all/08_networks.yml: `local.database` ->
`local.mariadb` (3306-3306) and `local.postgres` (5432-5432).
- roles/svc-db-mariadb/meta/services.yml: ports.local.database
-> ports.local.mariadb.
- roles/svc-db-postgres/meta/services.yml: ports.local.database
-> ports.local.postgres.
- roles/svc-db-{mariadb,postgres}/vars/main.yml: lookups follow
the new path.
Also add `TestPortBandsDisjoint.test_no_overlapping_bands_in_same_scope`
in tests/lint/repository/test_role_meta_layout.py: rejects any
two PORT_BANDS entries within the same scope whose ranges
intersect, with a precise overlap range in the failure message.
Cross-scope overlaps remain intentional (different bind contexts).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
d97b16e9f1
commit
1e94b14dd4
6 files changed
+62
-5
No files matched your search
@@ -54,8 +54,11 @@ PORT_BANDS:
|
||||
oauth2:
|
||||
start: 16480
|
||||
end: 16519
|
||||
database:
|
||||
mariadb:
|
||||
start: 3306
|
||||
end: 3306
|
||||
postgres:
|
||||
start: 5432
|
||||
end: 5432
|
||||
ldap:
|
||||
start: 389
|
||||
|
||||
@@ -13,5 +13,5 @@ mariadb:
|
||||
pids_limit: 1024
|
||||
ports:
|
||||
local:
|
||||
database: 3306
|
||||
mariadb: 3306
|
||||
lifecycle: beta
|
||||
@@ -9,7 +9,7 @@ MARIADB_VOLUME: "{{ lookup('config', application_id, 'volumes.data') }}"
|
||||
MARIADB_IMAGE: "{{ lookup('config', application_id, 'services.' ~ entity_name ~ '.image') }}"
|
||||
MARIADB_VERSION: "{{ lookup('config', application_id, 'services.' ~ entity_name ~ '.version') }}"
|
||||
MARIADB_NAME: "{{ lookup('config', application_id, 'services.' ~ entity_name ~ '.name') }}"
|
||||
MARIADB_PORT: "{{ database_port | default(lookup('config', application_id, 'services.mariadb.ports.local.database')) }}"
|
||||
MARIADB_PORT: "{{ database_port | default(lookup('config', application_id, 'services.mariadb.ports.local.mariadb')) }}"
|
||||
MARIADB_HOST: "127.0.0.1"
|
||||
MARIADB_CUSTOM_IMAGE: "{{ entity_name }}_custom:{{ MARIADB_VERSION }}"
|
||||
MARIADB_HEALTHCHECK_DB: "{{ SOFTWARE_DOMAIN | regex_replace('[^a-z0-9]+', '_') }}_healthcheck"
|
||||
|
||||
@@ -13,5 +13,5 @@ postgres:
|
||||
pids_limit: 1024
|
||||
ports:
|
||||
local:
|
||||
database: 5432
|
||||
postgres: 5432
|
||||
lifecycle: beta
|
||||
@@ -14,7 +14,7 @@ POSTGRES_VERSION_MAJOR: "{{ POSTGRES_VERSION | regex_replace('
|
||||
POSTGRES_NETWORK_NAME: "{{ application_id | get_entity_name }}"
|
||||
POSTGRES_SUBNET: "{{ lookup('config', 'svc-db-postgres', 'server.networks.local.subnet') }}"
|
||||
POSTGRES_PASSWORD: "{{ lookup('config', application_id, 'credentials.POSTGRES_PASSWORD') }}"
|
||||
POSTGRES_PORT: "{{ database_port | default(lookup('config', application_id, 'services.postgres.ports.local.database')) }}"
|
||||
POSTGRES_PORT: "{{ database_port | default(lookup('config', application_id, 'services.postgres.ports.local.postgres')) }}"
|
||||
POSTGRES_EXPOSE_LOCAL: True # Exposes the db to localhost, almost everytime neccessary
|
||||
POSTGRES_CUSTOM_IMAGE: "{{ entity_name }}_custom:{{ POSTGRES_VERSION }}"
|
||||
POSTGRES_LOCAL_HOST: "127.0.0.1"
|
||||
|
||||
@@ -337,6 +337,60 @@ class TestPortBandMembership(unittest.TestCase):
|
||||
)
|
||||
|
||||
|
||||
class TestPortBandsDisjoint(unittest.TestCase):
|
||||
"""PORT_BANDS within a single scope MUST be pairwise disjoint, otherwise
|
||||
a port could legitimately belong to two categories at once and the
|
||||
suggester / band-membership lint would silently route it to the
|
||||
wrong category. Cross-scope overlaps (e.g. local.http=8001-8099 and
|
||||
public.https=...) are intentional and not checked here."""
|
||||
|
||||
def test_no_overlapping_bands_in_same_scope(self):
|
||||
from utils.meta.port_bands import load_port_bands
|
||||
|
||||
offenders: list[str] = []
|
||||
for scope, scope_block in (load_port_bands() or {}).items():
|
||||
if not isinstance(scope_block, dict):
|
||||
continue
|
||||
ranges: list[tuple[str, int, int]] = []
|
||||
for category, entry in scope_block.items():
|
||||
if not isinstance(entry, dict):
|
||||
continue
|
||||
start = entry.get("start")
|
||||
end = entry.get("end")
|
||||
if not isinstance(start, int) or not isinstance(end, int):
|
||||
continue
|
||||
if start > end:
|
||||
offenders.append(
|
||||
f"PORT_BANDS.{scope}.{category}: start ({start}) > end ({end})"
|
||||
)
|
||||
continue
|
||||
ranges.append((category, start, end))
|
||||
|
||||
ranges.sort(key=lambda r: (r[1], r[2]))
|
||||
for i in range(len(ranges)):
|
||||
cat_a, start_a, end_a = ranges[i]
|
||||
for j in range(i + 1, len(ranges)):
|
||||
cat_b, start_b, end_b = ranges[j]
|
||||
if start_b > end_a:
|
||||
break
|
||||
overlap_start = max(start_a, start_b)
|
||||
overlap_end = min(end_a, end_b)
|
||||
offenders.append(
|
||||
f"PORT_BANDS.{scope}.{cat_a}={start_a}-{end_a} overlaps "
|
||||
f"PORT_BANDS.{scope}.{cat_b}={start_b}-{end_b} on "
|
||||
f"{overlap_start}-{overlap_end}"
|
||||
)
|
||||
|
||||
if offenders:
|
||||
self.fail(
|
||||
"PORT_BANDS overlap detected (req-009):\n"
|
||||
+ "\n".join(f" - {o}" for o in offenders)
|
||||
+ "\n\nFix: shrink one of the overlapping ranges in "
|
||||
+ "group_vars/all/08_networks.yml so each port belongs to "
|
||||
+ "at most one (scope, category) pair."
|
||||
)
|
||||
|
||||
|
||||
class TestNoComposeWrapperInVariants(unittest.TestCase):
|
||||
"""Per req-008 the file root of meta/services.yml IS the services map.
|
||||
Variant overrides in meta/variants.yml MUST follow the same shape: top
|
||||
|
||||
Reference in new issue
Block a user