1
0
mirror of https://github.com/github/octodns.git synced 2024-05-11 05:55:00 +00:00

Add subnet ordering validation

This commit is contained in:
Viranch Mehta
2023-04-09 09:17:42 -07:00
parent 47a898b1dc
commit 96f09cb4e5
3 changed files with 34 additions and 12 deletions

View File

@@ -221,6 +221,7 @@ class _DynamicMixin(object):
pools_seen = set()
geos_seen = {}
subnets_seen = {}
if not isinstance(rules, (list, tuple)):
reasons.append('rules must be a list')
@@ -259,6 +260,30 @@ class _DynamicMixin(object):
reasons.append(f'rule {rule_num} duplicate default')
seen_default = True
if not isinstance(subnets, (list, tuple)):
reasons.append(f'rule {rule_num} subnets must be a list')
else:
for subnet in subnets:
reasons.extend(
Subnets.validate(subnet, f'rule {rule_num} ')
)
networks = [Subnets.parse(s) for s in subnets]
# sort subnets from largest to smallest so that we can
# detect rule that have needlessly targeted a more specific
# subnet along with a larger subnet that already contains it
for subnet in sorted(networks):
for seen, where in subnets_seen.items():
if subnet == seen:
reasons.append(
f'rule {rule_num} targets subnet {subnet} which has previously been seen in rule {where}'
)
elif subnet.subnet_of(seen):
reasons.append(
f'rule {rule_num} targets subnet {subnet} which is more specific than the previously seen {seen} in rule {where}'
)
subnets_seen[subnet] = rule_num
if not isinstance(geos, (list, tuple)):
reasons.append(f'rule {rule_num} geos must be a list')
else:
@@ -285,16 +310,10 @@ class _DynamicMixin(object):
geos_seen[geo] = rule_num
if not isinstance(subnets, (list, tuple)):
reasons.append(f'rule {rule_num} subnets must be a list')
else:
for subnet in subnets:
reasons.extend(
Subnets.validate(subnet, f'rule {rule_num} ')
)
if 'geos' in rules[-1]:
reasons.append('final rule has "geos" and is not catchall')
if 'subnets' in rules[-1] or 'geos' in rules[-1]:
reasons.append(
'final rule has "subnets" and/or "geos" and is not catchall'
)
return reasons, pools_seen

View File

@@ -14,7 +14,7 @@ class Subnets(object):
reasons = []
try:
ipaddress.ip_network(subnet)
cls.parse(subnet)
except ValueError:
reasons.append(f'{prefix}invalid subnet "{subnet}"')

View File

@@ -1350,4 +1350,7 @@ class TestRecordDynamic(TestCase):
{'geos': ('EU', 'NA'), 'pool': 'iad'},
]
reasons, pools_seen = _DynamicMixin._validate_rules(pools, rules)
self.assertEqual(['final rule has "geos" and is not catchall'], reasons)
self.assertEqual(
['final rule has "subnets" and/or "geos" and is not catchall'],
reasons,
)