Browse Source

Impliment Dynamic rule geo validation

pull/307/head
Ross McFarland 7 years ago
parent
commit
ccd9038a38
No known key found for this signature in database GPG Key ID: 61C10C4FC8FE4A89
3 changed files with 152 additions and 7 deletions
  1. +33
    -1
      octodns/record.py
  2. +12
    -6
      tests/config/dynamic.tests.yaml
  3. +107
    -0
      tests/test_octodns_record.py

+ 33
- 1
octodns/record.py View File

@ -406,6 +406,22 @@ class _DynamicPool(object):
return '{}'.format(self.data) 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): class _DynamicRule(object):
def __init__(self, i, data): def __init__(self, i, data):
@ -517,6 +533,8 @@ class _DynamicMixin(object):
elif not rules: elif not rules:
reasons.append('missing rules') reasons.append('missing rules')
else: else:
seen_default = False
for rule_num, rule in enumerate(rules): for rule_num, rule in enumerate(rules):
rule_num += 1 rule_num += 1
try: try:
@ -532,7 +550,21 @@ class _DynamicMixin(object):
reasons.append('rule {} undefined pool "{}"' reasons.append('rule {} undefined pool "{}"'
.format(rule_num, 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 return reasons


+ 12
- 6
tests/config/dynamic.tests.yaml View File

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


+ 107
- 0
tests/test_octodns_record.py View File

@ -2688,6 +2688,113 @@ class TestDynamicRecords(TestCase):
self.assertEquals(["rule 1 undefined pool \"non-existant\""], self.assertEquals(["rule 1 undefined pool \"non-existant\""],
ctx.exception.reasons) 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): def test_dynamic_lenient(self):
# Missing pools # Missing pools
a_data = { a_data = {


Loading…
Cancel
Save