mirror of
https://github.com/github/octodns.git
synced 2024-05-11 05:55:00 +00:00
Implement Dync populate dynamic, flesh out testing for all but dyn
This commit is contained in:
@@ -466,7 +466,7 @@ class DynProvider(BaseProvider):
|
|||||||
values = []
|
values = []
|
||||||
data = {
|
data = {
|
||||||
'dynamic': {
|
'dynamic': {
|
||||||
'pool': pools,
|
'pools': pools,
|
||||||
'rules': rules,
|
'rules': rules,
|
||||||
},
|
},
|
||||||
'type': _type,
|
'type': _type,
|
||||||
@@ -523,11 +523,13 @@ class DynProvider(BaseProvider):
|
|||||||
# Geo
|
# Geo
|
||||||
geo = ruleset.criteria['geoip']
|
geo = ruleset.criteria['geoip']
|
||||||
geos = []
|
geos = []
|
||||||
# TODO: we need to reconstitude geos here :-/
|
# Dyn uses the same 2-letter codes as octoDNS (except for
|
||||||
|
# continents) but it doesn't have the hierary, e.g. US is
|
||||||
|
# just US, not NA-US. We'll have to map these things back
|
||||||
for code in geo['country']:
|
for code in geo['country']:
|
||||||
geos.append(code)
|
geos.append(GeoCodes.country_to_code(code))
|
||||||
for code in geo['province']:
|
for code in geo['province']:
|
||||||
geos.append(code)
|
geos.append(GeoCodes.province_to_code(code.upper()))
|
||||||
for code in geo['region']:
|
for code in geo['region']:
|
||||||
geos.append(self.REGION_CODES_LOOKUP[int(code)])
|
geos.append(self.REGION_CODES_LOOKUP[int(code)])
|
||||||
rule['geos'] = geos
|
rule['geos'] = geos
|
||||||
@@ -543,8 +545,6 @@ class DynProvider(BaseProvider):
|
|||||||
|
|
||||||
pprint(data)
|
pprint(data)
|
||||||
|
|
||||||
raise Exception('boom')
|
|
||||||
|
|
||||||
name = zone.hostname_from_fqdn(fqdn)
|
name = zone.hostname_from_fqdn(fqdn)
|
||||||
record = Record.new(zone, name, data, source=self, lenient=lenient)
|
record = Record.new(zone, name, data, source=self, lenient=lenient)
|
||||||
zone.add_record(record, lenient=lenient)
|
zone.add_record(record, lenient=lenient)
|
||||||
@@ -1012,6 +1012,10 @@ class DynProvider(BaseProvider):
|
|||||||
def _mod_dynamic_rulesets(self, td, change):
|
def _mod_dynamic_rulesets(self, td, change):
|
||||||
new = change.new
|
new = change.new
|
||||||
|
|
||||||
|
# TODO: make sure we can update TTLs
|
||||||
|
if td.ttl != new.ttl:
|
||||||
|
td.ttl = new.ttl
|
||||||
|
|
||||||
# Get existing pools. This should be simple, but it's not b/c the dyn
|
# Get existing pools. This should be simple, but it's not b/c the dyn
|
||||||
# api is a POS. We need all response pools so we can GC and check to
|
# api is a POS. We need all response pools so we can GC and check to
|
||||||
# make sure that what we're after doesn't already exist.
|
# make sure that what we're after doesn't already exist.
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ import re
|
|||||||
from .geo import GeoCodes
|
from .geo import GeoCodes
|
||||||
|
|
||||||
|
|
||||||
|
from pprint import pprint
|
||||||
|
|
||||||
|
|
||||||
class Change(object):
|
class Change(object):
|
||||||
|
|
||||||
def __init__(self, existing, new):
|
def __init__(self, existing, new):
|
||||||
@@ -384,7 +387,24 @@ class _DynamicPool(object):
|
|||||||
|
|
||||||
def __init__(self, _id, data):
|
def __init__(self, _id, data):
|
||||||
self._id = _id
|
self._id = _id
|
||||||
self.data = data
|
|
||||||
|
pprint(['before', data])
|
||||||
|
|
||||||
|
values = [
|
||||||
|
{
|
||||||
|
'value': d['value'],
|
||||||
|
'weight': d.get('weight', 1),
|
||||||
|
} for d in data['values']
|
||||||
|
]
|
||||||
|
values.sort(key=lambda d: d['value'])
|
||||||
|
|
||||||
|
fallback = data.get('fallback', None)
|
||||||
|
self.data = {
|
||||||
|
'fallback': fallback if fallback != 'default' else None,
|
||||||
|
'values': values,
|
||||||
|
}
|
||||||
|
|
||||||
|
pprint(['after', self.data])
|
||||||
|
|
||||||
def _data(self):
|
def _data(self):
|
||||||
return self.data
|
return self.data
|
||||||
@@ -403,12 +423,30 @@ class _DynamicRule(object):
|
|||||||
|
|
||||||
def __init__(self, i, data):
|
def __init__(self, i, data):
|
||||||
self.i = i
|
self.i = i
|
||||||
self.data = data
|
|
||||||
|
pprint(['before', data])
|
||||||
|
|
||||||
|
self.data = {}
|
||||||
|
try:
|
||||||
|
self.data['pool'] = data['pool']
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
self.data['geos'] = sorted(data['geos'])
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
pprint(['after', self.data])
|
||||||
|
|
||||||
def _data(self):
|
def _data(self):
|
||||||
return self.data
|
return self.data
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
|
pprint([
|
||||||
|
self.data,
|
||||||
|
other.data,
|
||||||
|
self.data == other.data,
|
||||||
|
])
|
||||||
return self.data == other.data
|
return self.data == other.data
|
||||||
|
|
||||||
def __ne__(self, other):
|
def __ne__(self, other):
|
||||||
|
|||||||
@@ -2,11 +2,13 @@
|
|||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
|
from logging import getLogger
|
||||||
|
|
||||||
from .geo_data import geo_data
|
from .geo_data import geo_data
|
||||||
|
|
||||||
|
|
||||||
class GeoCodes(object):
|
class GeoCodes(object):
|
||||||
__COUNTRIES = None
|
log = getLogger('GeoCodes')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def validate(cls, code, prefix):
|
def validate(cls, code, prefix):
|
||||||
@@ -50,3 +52,20 @@ class GeoCodes(object):
|
|||||||
'country_code': country_code,
|
'country_code': country_code,
|
||||||
'province_code': province_code,
|
'province_code': province_code,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def country_to_code(cls, country):
|
||||||
|
for continent, countries in geo_data.items():
|
||||||
|
if country in countries:
|
||||||
|
return '{}-{}'.format(continent, country)
|
||||||
|
cls.log.warn('country_to_code: unrecognized country "%s"', country)
|
||||||
|
return
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def province_to_code(cls, province):
|
||||||
|
# We get to cheat on this one since we only support provinces in NA-US
|
||||||
|
if province not in geo_data['NA']['US']['provinces']:
|
||||||
|
cls.log.warn('country_to_code: unrecognized province "%s"',
|
||||||
|
province)
|
||||||
|
return
|
||||||
|
return 'NA-US-{}'.format(province)
|
||||||
|
|||||||
@@ -1906,10 +1906,11 @@ class TestDynamicRecords(TestCase):
|
|||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
'two': {
|
'two': {
|
||||||
|
# Testing out of order value sorting here
|
||||||
'values': [{
|
'values': [{
|
||||||
'value': '4.4.4.4',
|
|
||||||
}, {
|
|
||||||
'value': '5.5.5.5',
|
'value': '5.5.5.5',
|
||||||
|
}, {
|
||||||
|
'value': '4.4.4.4',
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
'three': {
|
'three': {
|
||||||
@@ -1948,10 +1949,24 @@ class TestDynamicRecords(TestCase):
|
|||||||
|
|
||||||
pools = dynamic.pools
|
pools = dynamic.pools
|
||||||
self.assertTrue(pools)
|
self.assertTrue(pools)
|
||||||
self.assertEquals(a_data['dynamic']['pools']['one'], pools['one'].data)
|
self.assertEquals({
|
||||||
self.assertEquals(a_data['dynamic']['pools']['two'], pools['two'].data)
|
'value': '3.3.3.3',
|
||||||
self.assertEquals(a_data['dynamic']['pools']['three'],
|
'weight': 1,
|
||||||
pools['three'].data)
|
}, pools['one'].data['values'][0])
|
||||||
|
self.assertEquals([{
|
||||||
|
'value': '4.4.4.4',
|
||||||
|
'weight': 1,
|
||||||
|
}, {
|
||||||
|
'value': '5.5.5.5',
|
||||||
|
'weight': 1,
|
||||||
|
}], pools['two'].data['values'])
|
||||||
|
self.assertEquals([{
|
||||||
|
'weight': 10,
|
||||||
|
'value': '4.4.4.4',
|
||||||
|
}, {
|
||||||
|
'weight': 12,
|
||||||
|
'value': '5.5.5.5',
|
||||||
|
}], pools['three'].data['values'])
|
||||||
|
|
||||||
rules = dynamic.rules
|
rules = dynamic.rules
|
||||||
self.assertTrue(rules)
|
self.assertTrue(rules)
|
||||||
@@ -1994,10 +2009,11 @@ class TestDynamicRecords(TestCase):
|
|||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
'two': {
|
'two': {
|
||||||
|
# Testing out of order value sorting here
|
||||||
'values': [{
|
'values': [{
|
||||||
'value': '2601:642:500:e210:62f8:1dff:feb8:9474',
|
|
||||||
}, {
|
|
||||||
'value': '2601:642:500:e210:62f8:1dff:feb8:9475',
|
'value': '2601:642:500:e210:62f8:1dff:feb8:9475',
|
||||||
|
}, {
|
||||||
|
'value': '2601:642:500:e210:62f8:1dff:feb8:9474',
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
'three': {
|
'three': {
|
||||||
@@ -2036,12 +2052,24 @@ class TestDynamicRecords(TestCase):
|
|||||||
|
|
||||||
pools = dynamic.pools
|
pools = dynamic.pools
|
||||||
self.assertTrue(pools)
|
self.assertTrue(pools)
|
||||||
self.assertEquals(aaaa_data['dynamic']['pools']['one'],
|
self.assertEquals({
|
||||||
pools['one'].data)
|
'value': '2601:642:500:e210:62f8:1dff:feb8:9473',
|
||||||
self.assertEquals(aaaa_data['dynamic']['pools']['two'],
|
'weight': 1,
|
||||||
pools['two'].data)
|
}, pools['one'].data['values'][0])
|
||||||
self.assertEquals(aaaa_data['dynamic']['pools']['three'],
|
self.assertEquals([{
|
||||||
pools['three'].data)
|
'value': '2601:642:500:e210:62f8:1dff:feb8:9474',
|
||||||
|
'weight': 1,
|
||||||
|
}, {
|
||||||
|
'value': '2601:642:500:e210:62f8:1dff:feb8:9475',
|
||||||
|
'weight': 1,
|
||||||
|
}], pools['two'].data['values'])
|
||||||
|
self.assertEquals([{
|
||||||
|
'weight': 10,
|
||||||
|
'value': '2601:642:500:e210:62f8:1dff:feb8:9476',
|
||||||
|
}, {
|
||||||
|
'weight': 12,
|
||||||
|
'value': '2601:642:500:e210:62f8:1dff:feb8:9477',
|
||||||
|
}], pools['three'].data['values'])
|
||||||
|
|
||||||
rules = dynamic.rules
|
rules = dynamic.rules
|
||||||
self.assertTrue(rules)
|
self.assertTrue(rules)
|
||||||
@@ -2094,12 +2122,21 @@ class TestDynamicRecords(TestCase):
|
|||||||
|
|
||||||
pools = dynamic.pools
|
pools = dynamic.pools
|
||||||
self.assertTrue(pools)
|
self.assertTrue(pools)
|
||||||
self.assertEquals(cname_data['dynamic']['pools']['one'],
|
self.assertEquals({
|
||||||
pools['one'].data)
|
'value': 'one.cname.target.',
|
||||||
self.assertEquals(cname_data['dynamic']['pools']['two'],
|
'weight': 1,
|
||||||
pools['two'].data)
|
}, pools['one'].data['values'][0])
|
||||||
self.assertEquals(cname_data['dynamic']['pools']['three'],
|
self.assertEquals({
|
||||||
pools['three'].data)
|
'value': 'two.cname.target.',
|
||||||
|
'weight': 1,
|
||||||
|
}, pools['two'].data['values'][0])
|
||||||
|
self.assertEquals([{
|
||||||
|
'value': 'three-1.cname.target.',
|
||||||
|
'weight': 12,
|
||||||
|
}, {
|
||||||
|
'value': 'three-2.cname.target.',
|
||||||
|
'weight': 32,
|
||||||
|
}], pools['three'].data['values'])
|
||||||
|
|
||||||
rules = dynamic.rules
|
rules = dynamic.rules
|
||||||
self.assertTrue(rules)
|
self.assertTrue(rules)
|
||||||
@@ -2906,9 +2943,10 @@ class TestDynamicRecords(TestCase):
|
|||||||
a_data = {
|
a_data = {
|
||||||
'dynamic': {
|
'dynamic': {
|
||||||
'rules': [{
|
'rules': [{
|
||||||
'pools': {
|
'geos': ['EU'],
|
||||||
1: 'one',
|
'pool': 'two',
|
||||||
}
|
}, {
|
||||||
|
'pool': 'one',
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
'ttl': 60,
|
'ttl': 60,
|
||||||
@@ -2928,7 +2966,19 @@ class TestDynamicRecords(TestCase):
|
|||||||
a_data = {
|
a_data = {
|
||||||
'dynamic': {
|
'dynamic': {
|
||||||
'pools': {
|
'pools': {
|
||||||
'one': '1.1.1.1',
|
'one': {
|
||||||
|
'values': [{
|
||||||
|
'value': '3.3.3.3',
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
'two': {
|
||||||
|
'values': [{
|
||||||
|
'value': '4.4.4.4',
|
||||||
|
}, {
|
||||||
|
'value': '5.5.5.5',
|
||||||
|
'weight': 2,
|
||||||
|
}]
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'ttl': 60,
|
'ttl': 60,
|
||||||
@@ -2941,11 +2991,82 @@ class TestDynamicRecords(TestCase):
|
|||||||
a = Record.new(self.zone, 'bad', a_data, lenient=True)
|
a = Record.new(self.zone, 'bad', a_data, lenient=True)
|
||||||
self.assertEquals({
|
self.assertEquals({
|
||||||
'pools': {
|
'pools': {
|
||||||
'one': '1.1.1.1',
|
'one': {
|
||||||
|
'fallback': None,
|
||||||
|
'values': [{
|
||||||
|
'value': '3.3.3.3',
|
||||||
|
'weight': 1,
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
'two': {
|
||||||
|
'fallback': None,
|
||||||
|
'values': [{
|
||||||
|
'value': '4.4.4.4',
|
||||||
|
'weight': 1,
|
||||||
|
}, {
|
||||||
|
'value': '5.5.5.5',
|
||||||
|
'weight': 2,
|
||||||
|
}]
|
||||||
|
},
|
||||||
},
|
},
|
||||||
'rules': [],
|
'rules': [],
|
||||||
}, a._data()['dynamic'])
|
}, a._data()['dynamic'])
|
||||||
|
|
||||||
|
# rule without pool
|
||||||
|
a_data = {
|
||||||
|
'dynamic': {
|
||||||
|
'pools': {
|
||||||
|
'one': {
|
||||||
|
'values': [{
|
||||||
|
'value': '3.3.3.3',
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
'two': {
|
||||||
|
'values': [{
|
||||||
|
'value': '4.4.4.4',
|
||||||
|
}, {
|
||||||
|
'value': '5.5.5.5',
|
||||||
|
'weight': 2,
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'rules': [{
|
||||||
|
'geos': ['EU'],
|
||||||
|
'pool': 'two',
|
||||||
|
}, {
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
'ttl': 60,
|
||||||
|
'type': 'A',
|
||||||
|
'values': [
|
||||||
|
'1.1.1.1',
|
||||||
|
'2.2.2.2',
|
||||||
|
],
|
||||||
|
}
|
||||||
|
a = Record.new(self.zone, 'bad', a_data, lenient=True)
|
||||||
|
self.assertEquals({
|
||||||
|
'pools': {
|
||||||
|
'one': {
|
||||||
|
'fallback': None,
|
||||||
|
'values': [{
|
||||||
|
'value': '3.3.3.3',
|
||||||
|
'weight': 1,
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
'two': {
|
||||||
|
'fallback': None,
|
||||||
|
'values': [{
|
||||||
|
'value': '4.4.4.4',
|
||||||
|
'weight': 1,
|
||||||
|
}, {
|
||||||
|
'value': '5.5.5.5',
|
||||||
|
'weight': 2,
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'rules': a_data['dynamic']['rules'],
|
||||||
|
}, a._data()['dynamic'])
|
||||||
|
|
||||||
def test_dynamic_changes(self):
|
def test_dynamic_changes(self):
|
||||||
simple = SimpleProvider()
|
simple = SimpleProvider()
|
||||||
dynamic = DynamicProvider()
|
dynamic = DynamicProvider()
|
||||||
@@ -2953,17 +3074,24 @@ class TestDynamicRecords(TestCase):
|
|||||||
a_data = {
|
a_data = {
|
||||||
'dynamic': {
|
'dynamic': {
|
||||||
'pools': {
|
'pools': {
|
||||||
'one': '3.3.3.3',
|
'one': {
|
||||||
'two': [
|
'values': [{
|
||||||
'4.4.4.4',
|
'value': '3.3.3.3',
|
||||||
'5.5.5.5',
|
}]
|
||||||
],
|
},
|
||||||
|
'two': {
|
||||||
|
'values': [{
|
||||||
|
'value': '4.4.4.4',
|
||||||
|
}, {
|
||||||
|
'value': '5.5.5.5',
|
||||||
|
}]
|
||||||
|
},
|
||||||
},
|
},
|
||||||
'rules': [{
|
'rules': [{
|
||||||
'pools': {
|
'geos': ['EU'],
|
||||||
100: 'one',
|
'pool': 'two',
|
||||||
200: 'two',
|
}, {
|
||||||
}
|
'pool': 'one',
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
'ttl': 60,
|
'ttl': 60,
|
||||||
@@ -2978,17 +3106,25 @@ class TestDynamicRecords(TestCase):
|
|||||||
b_data = {
|
b_data = {
|
||||||
'dynamic': {
|
'dynamic': {
|
||||||
'pools': {
|
'pools': {
|
||||||
'one': '3.3.3.5',
|
'one': {
|
||||||
'two': [
|
'values': [{
|
||||||
'4.4.4.4',
|
'value': '3.3.3.3',
|
||||||
'5.5.5.5',
|
}]
|
||||||
],
|
},
|
||||||
|
'two': {
|
||||||
|
'values': [{
|
||||||
|
'value': '4.4.4.4',
|
||||||
|
'weight': 2,
|
||||||
|
}, {
|
||||||
|
'value': '5.5.5.5',
|
||||||
|
}]
|
||||||
|
},
|
||||||
},
|
},
|
||||||
'rules': [{
|
'rules': [{
|
||||||
'pools': {
|
'geos': ['EU'],
|
||||||
100: 'one',
|
'pool': 'two',
|
||||||
200: 'two',
|
}, {
|
||||||
}
|
'pool': 'one',
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
'ttl': 60,
|
'ttl': 60,
|
||||||
@@ -3002,17 +3138,24 @@ class TestDynamicRecords(TestCase):
|
|||||||
c_data = {
|
c_data = {
|
||||||
'dynamic': {
|
'dynamic': {
|
||||||
'pools': {
|
'pools': {
|
||||||
'one': '3.3.3.3',
|
'one': {
|
||||||
'two': [
|
'values': [{
|
||||||
'4.4.4.4',
|
'value': '3.3.3.3',
|
||||||
'5.5.5.5',
|
}]
|
||||||
],
|
},
|
||||||
|
'two': {
|
||||||
|
'values': [{
|
||||||
|
'value': '4.4.4.4',
|
||||||
|
}, {
|
||||||
|
'value': '5.5.5.5',
|
||||||
|
}]
|
||||||
|
},
|
||||||
},
|
},
|
||||||
'rules': [{
|
'rules': [{
|
||||||
'pools': {
|
'geos': ['NA'],
|
||||||
100: 'one',
|
'pool': 'two',
|
||||||
300: 'two',
|
}, {
|
||||||
}
|
'pool': 'one',
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
'ttl': 60,
|
'ttl': 60,
|
||||||
|
|||||||
@@ -68,3 +68,13 @@ class TestRecordGeoCodes(TestCase):
|
|||||||
'country_code': 'US',
|
'country_code': 'US',
|
||||||
'province_code': 'CA',
|
'province_code': 'CA',
|
||||||
}, GeoCodes.parse('NA-US-CA'))
|
}, GeoCodes.parse('NA-US-CA'))
|
||||||
|
|
||||||
|
def test_country_to_code(self):
|
||||||
|
self.assertEquals('NA-US', GeoCodes.country_to_code('US'))
|
||||||
|
self.assertEquals('EU-GB', GeoCodes.country_to_code('GB'))
|
||||||
|
self.assertFalse(GeoCodes.country_to_code('XX'))
|
||||||
|
|
||||||
|
def test_province_to_code(self):
|
||||||
|
self.assertEquals('NA-US-OR', GeoCodes.province_to_code('OR'))
|
||||||
|
self.assertEquals('NA-US-KY', GeoCodes.province_to_code('KY'))
|
||||||
|
self.assertFalse(GeoCodes.province_to_code('XX'))
|
||||||
|
|||||||
Reference in New Issue
Block a user