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

Impliment Dynamic rule geo validation

This commit is contained in:
Ross McFarland
2018-12-05 16:42:38 -08:00
parent e16648ab1f
commit ccd9038a38
3 changed files with 152 additions and 7 deletions

View File

@@ -406,6 +406,22 @@ class _DynamicPool(object):
return '{}'.format(self.data)
class _DynamicRuleGeo(object):
geo_re = re.compile(r'^(?P<continent_code>\w\w)(-(?P<country_code>\w\w)'
r'(-(?P<subdivision_code>\w\w))?)?$')
@classmethod
def validate(cls, rule_num, code):
reasons = []
# TODO: ideally this would validate the actual code...
match = cls.geo_re.match(code)
if not match:
reasons.append('rule {} invalid geo "{}"'.format(rule_num, code))
return reasons
# TODO: flesh this out
class _DynamicRule(object):
def __init__(self, i, data):
@@ -517,6 +533,8 @@ class _DynamicMixin(object):
elif not rules:
reasons.append('missing rules')
else:
seen_default = False
for rule_num, rule in enumerate(rules):
rule_num += 1
try:
@@ -532,7 +550,21 @@ class _DynamicMixin(object):
reasons.append('rule {} undefined pool "{}"'
.format(rule_num, pool))
# TODO: validate GEOs if present
try:
geos = rule['geos']
except KeyError:
geos = []
if seen_default:
reasons.append('rule {} duplicate default'
.format(rule_num))
seen_default = True
if not isinstance(geos, (list, tuple)):
reasons.append('rule {} geos must be a list'
.format(rule_num))
else:
for geo in geos:
reasons.extend(_DynamicRuleGeo.validate(rule_num, geo))
return reasons

View File

@@ -21,9 +21,11 @@ a:
- value: 5.5.5.5
weight: 25
rules:
- geo: EU-UK
- geos:
- EU-UK
pool: iad
- geo: EU
- geos:
- EU
pool: ams
- geos:
- NA-US-CA
@@ -55,9 +57,11 @@ aaaa:
- value: 2601:642:500:e210:62f8:1dff:feb8:9476
weight: 2
rules:
- geo: EU-UK
- geos:
- EU-UK
pool: iad
- geo: EU
- geos:
- EU
pool: ams
- geos:
- NA-US-CA
@@ -88,9 +92,11 @@ cname:
- value: target-sea-2.unit.tests.
weight: 175
rules:
- geo: EU-UK
- geos:
- EU-UK
pool: iad
- geo: EU
- geos:
- EU
pool: ams
- geos:
- NA-US-CA

View File

@@ -2688,6 +2688,113 @@ class TestDynamicRecords(TestCase):
self.assertEquals(["rule 1 undefined pool \"non-existant\""],
ctx.exception.reasons)
# rule with invalid geos
a_data = {
'dynamic': {
'pools': {
'one': {
'values': [{
'value': '3.3.3.3',
}]
},
'two': {
'values': [{
'value': '4.4.4.4',
}, {
'value': '5.5.5.5',
}]
},
},
'rules': [{
'geos': 'NA-US-CA',
'pool': 'two',
}, {
'pool': 'one',
}],
},
'ttl': 60,
'type': 'A',
'values': [
'1.1.1.1',
'2.2.2.2',
],
}
with self.assertRaises(ValidationError) as ctx:
Record.new(self.zone, 'bad', a_data)
self.assertEquals(['rule 1 geos must be a list'],
ctx.exception.reasons)
# rule with invalid geo
a_data = {
'dynamic': {
'pools': {
'one': {
'values': [{
'value': '3.3.3.3',
}]
},
'two': {
'values': [{
'value': '4.4.4.4',
}, {
'value': '5.5.5.5',
}]
},
},
'rules': [{
'geos': ['invalid'],
'pool': 'two',
}, {
'pool': 'one',
}],
},
'ttl': 60,
'type': 'A',
'values': [
'1.1.1.1',
'2.2.2.2',
],
}
with self.assertRaises(ValidationError) as ctx:
Record.new(self.zone, 'bad', a_data)
self.assertEquals(['rule 1 invalid geo "invalid"'],
ctx.exception.reasons)
# multiple default rules
a_data = {
'dynamic': {
'pools': {
'one': {
'values': [{
'value': '3.3.3.3',
}]
},
'two': {
'values': [{
'value': '4.4.4.4',
}, {
'value': '5.5.5.5',
}]
},
},
'rules': [{
'pool': 'two',
}, {
'pool': 'one',
}],
},
'ttl': 60,
'type': 'A',
'values': [
'1.1.1.1',
'2.2.2.2',
],
}
with self.assertRaises(ValidationError) as ctx:
Record.new(self.zone, 'bad', a_data)
self.assertEquals(['rule 2 duplicate default'],
ctx.exception.reasons)
def test_dynamic_lenient(self):
# Missing pools
a_data = {