Files
computer-playbook/tests/unit/python/utils/networks/test_ownership.py
T
kevinveenbirkenbachandClaude Opus 5.5 0c54388951 fix(constructor): accept the legacy owners of networks and volumes in the pre-flight
Production hosts carry objects from before the compose project was named after the entity: galaxyserver's mariadb, openldap and postgres networks have no project label, and echoserver's openldap_data volume is labelled svc-db-openldap, the role id older deploys passed as -p. The pre-flight stopped both deploys although compose reuses such networks and volumes with a warning. A network named after its entity now passes without a label or with a declaring role id, still checked against its subnet; a volume passes with a declaring role id as well. A container does not, because compose cannot see a container of another project and fails on its name. A label naming another project still stops the deploy, and the volume message now says compose would hand the role another project's data instead of claiming it refuses the volume.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 18:07:15 +01:00

173 lines
6.6 KiB
Python

import unittest
from utils.networks.ownership import ownership_errors
DECLARED = {
"matomo": [("web-app-matomo", "192.168.31.0/24")],
"postgres": [("svc-db-postgres", "192.168.200.0/24")],
}
SHARED = {
"litellm": [
("web-app-litellm", "192.168.76.0/24"),
("svc-ai-litellm", "192.168.80.0/24"),
],
}
def _network(name, *subnets, project=None):
labels = {} if project is None else {"com.docker.compose.project": project}
return {
"Name": name,
"Labels": labels,
"IPAM": {"Config": [{"Subnet": subnet} for subnet in subnets]},
}
class TestOwnershipErrors(unittest.TestCase):
def test_networks_that_match_their_owner_pass(self):
networks = [
_network("matomo", "192.168.31.0/24", project="matomo"),
_network("postgres", "192.168.200.0/24", project="postgres"),
]
self.assertEqual(ownership_errors(networks, DECLARED), [])
def test_a_network_inside_its_widened_block_passes(self):
networks = [_network("matomo", "192.168.31.0/28", project="matomo")]
self.assertEqual(ownership_errors(networks, DECLARED), [])
def test_a_network_reaching_beyond_its_block_is_drift(self):
networks = [_network("matomo", "192.168.30.0/23", project="matomo")]
self.assertEqual(
ownership_errors(networks, DECLARED),
[
"network 'matomo' holds 192.168.30.0/23, but web-app-matomo declares 192.168.31.0/24"
],
)
def test_roles_sharing_an_entity_each_pass_with_their_subnet(self):
networks = [_network("litellm", "192.168.80.0/24", project="litellm")]
self.assertEqual(ownership_errors(networks, SHARED), [])
def test_roles_sharing_an_entity_name_every_accepted_subnet_on_drift(self):
networks = [_network("litellm", "192.168.90.0/24", project="litellm")]
self.assertEqual(
ownership_errors(networks, SHARED),
[
(
"network 'litellm' holds 192.168.90.0/24, but svc-ai-litellm "
"declares 192.168.80.0/24 or web-app-litellm declares 192.168.76.0/24"
)
],
)
def test_system_and_auto_addressed_networks_pass(self):
networks = [
_network("bridge", "172.17.0.0/16"),
{"Name": "host", "Labels": {}, "IPAM": {"Config": []}},
{"Name": "none", "Labels": None, "IPAM": {"Config": None}},
_network("matomo_default", "10.208.3.0/24", project="matomo"),
]
self.assertEqual(ownership_errors(networks, DECLARED), [])
def test_an_ipv6_subnet_next_to_the_declared_one_passes(self):
networks = [
_network("matomo", "192.168.31.0/24", "fd00:31::/64", project="matomo")
]
self.assertEqual(ownership_errors(networks, DECLARED), [])
def test_a_drifted_subnet_names_the_owner_and_both_subnets(self):
networks = [_network("matomo", "192.168.40.0/24", project="matomo")]
self.assertEqual(
ownership_errors(networks, DECLARED),
[
"network 'matomo' holds 192.168.40.0/24, but web-app-matomo declares 192.168.31.0/24"
],
)
def test_a_network_without_a_subnet_is_drift(self):
networks = [
{"Name": "matomo", "Labels": {"com.docker.compose.project": "matomo"}}
]
self.assertEqual(
ownership_errors(networks, DECLARED),
[
"network 'matomo' holds no subnet, but web-app-matomo declares 192.168.31.0/24"
],
)
def test_a_foreign_compose_project_is_reported(self):
networks = [_network("matomo", "192.168.31.0/24", project="nextcloud")]
self.assertEqual(
ownership_errors(networks, DECLARED),
[
(
"network 'matomo' belongs to compose project 'nextcloud', "
"but it is the network of web-app-matomo"
)
],
)
def test_an_unlabeled_network_on_its_subnet_passes(self):
networks = [
_network("matomo", "192.168.31.0/24"),
_network("postgres", "192.168.200.0/24"),
]
self.assertEqual(ownership_errors(networks, DECLARED), [])
def test_a_network_labelled_with_its_role_id_passes(self):
networks = [_network("postgres", "192.168.200.0/24", project="svc-db-postgres")]
self.assertEqual(ownership_errors(networks, DECLARED), [])
def test_an_unlabeled_network_off_its_subnet_is_still_drift(self):
networks = [_network("matomo", "192.168.40.0/24")]
self.assertEqual(
ownership_errors(networks, DECLARED),
[
"network 'matomo' holds 192.168.40.0/24, but web-app-matomo declares 192.168.31.0/24"
],
)
def test_a_foreign_network_on_a_declared_subnet_is_reported(self):
networks = [_network("legacy", "192.168.200.0/25")]
self.assertEqual(
ownership_errors(networks, DECLARED),
[
(
"network 'legacy' occupies 192.168.200.0/25, which svc-db-postgres "
"declares for its network 'postgres'"
)
],
)
def test_a_secondary_network_of_the_owning_project_on_its_subnet_passes(self):
declared = {"bigbluebutton": [("web-app-bigbluebutton", "10.7.7.0/24")]}
networks = [
_network("bigbluebutton_bbb-net", "10.7.7.0/24", project="bigbluebutton")
]
self.assertEqual(ownership_errors(networks, declared), [])
def test_a_foreign_project_on_a_declared_subnet_is_still_reported(self):
networks = [_network("legacy_net", "192.168.200.0/25", project="legacy")]
self.assertEqual(len(ownership_errors(networks, DECLARED)), 1)
def test_an_owner_on_another_owners_subnet_reports_drift_and_clash(self):
networks = [_network("matomo", "192.168.200.0/24", project="matomo")]
self.assertEqual(
ownership_errors(networks, DECLARED),
[
"network 'matomo' holds 192.168.200.0/24, but web-app-matomo declares 192.168.31.0/24",
(
"network 'matomo' occupies 192.168.200.0/24, which svc-db-postgres "
"declares for its network 'postgres'"
),
],
)
def test_an_ipv6_subnet_never_clashes_with_an_ipv4_declaration(self):
networks = [_network("v6only", "::c0a8:1f00/120")]
self.assertEqual(ownership_errors(networks, DECLARED), [])
if __name__ == "__main__":
unittest.main()