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

Rough draft/expirimentation on dynamic creation

This commit is contained in:
Ross McFarland
2019-12-09 14:30:02 -08:00
parent 4fd2daa8a9
commit f0bc9add22

View File

@@ -70,13 +70,54 @@ class Ns1Provider(BaseProvider):
class: octodns.provider.ns1.Ns1Provider
api_key: env/NS1_API_KEY
'''
SUPPORTS_GEO = True
SUPPORTS_DYNAMIC = False
SUPPORTS_GEO = False
SUPPORTS_DYNAMIC = True
SUPPORTS = set(('A', 'AAAA', 'ALIAS', 'CAA', 'CNAME', 'MX', 'NAPTR',
'NS', 'PTR', 'SPF', 'SRV', 'TXT'))
ZONE_NOT_FOUND_MESSAGE = 'server error: zone not found'
_DYNAMIC_FILTERS = [{
'config': {},
'filter': 'up'
}, {
'config': {},
'filter': u'geotarget_regional'
}, {
'config': {},
'filter': u'select_first_region'
}, {
'config': {
'eliminate': u'1'
},
'filter': 'priority'
}, {
'config': {},
'filter': u'weighted_shuffle'
}, {
'config': {
'N': u'1'
},
'filter': u'select_first_n'
}]
_REGION_TO_CONTINENT = {
'AFRICA': 'AF',
'ASIAPAC': 'AS',
'EUROPE': 'EU',
'SOUTH-AMERICA': 'SA',
'US-CENTRAL': 'NA',
'US-EAST': 'NA',
'US-WEST': 'NA',
}
_CONTINENT_TO_REGIONS = {
'AF': ('AFRICA',),
'AS': ('ASIAPAC',),
'EU': ('EUROPE',),
'SA': ('SOUTH-AMERICA',),
# TODO: what about CA, MX, and all the other NA countries?
'NA': ('US-CENTRAL', 'US-EAST', 'US-WEST'),
}
def __init__(self, id, api_key, retry_count=4, *args, **kwargs):
self.log = getLogger('Ns1Provider[{}]'.format(id))
self.log.debug('__init__: id=%s, api_key=***, retry_count=%d', id,
@@ -282,9 +323,124 @@ class Ns1Provider(BaseProvider):
len(zone.records) - before, exists)
return exists
def _encode_notes(self, data):
return ' '.join(['{}:{}'.format(k, v)
for k, v in sorted(data.items())])
def _params_for_A(self, record):
params = {'answers': record.values, 'ttl': record.ttl}
if hasattr(record, 'geo'):
params = {'ttl': record.ttl}
if hasattr(record, 'dynamic'):
pools = record.dynamic.pools
# Convert rules to regions
regions = {}
for i, rule in enumerate(record.dynamic.rules):
pool_name = rule.data['pool']
notes = {
'rule-order': i,
}
fallback = pools[pool_name].data.get('fallback', None)
if fallback:
notes['fallback'] = fallback
country = set()
georegion = set()
us_state = set()
for geo in rule.data.get('geos', []):
n = len(geo)
if n == 8:
# US state
us_state.add(geo[-2:])
elif n == 5:
# Country
country.add(geo[-2:])
else:
# Continent
georegion.update(self._CONTINENT_TO_REGIONS[geo])
meta = {
'note': self._encode_notes(notes),
}
if georegion:
meta['georegion'] = sorted(georegion)
if country:
meta['country'] = sorted(country)
if us_state:
meta['us_state'] = sorted(us_state)
regions[pool_name] = {
'meta': meta,
}
# Build a list of primary values for each pool
pool_answers = defaultdict(list)
for pool_name, pool in sorted(pools.items()):
for value in pool.data['values']:
pool_answers[pool_name].append({
'answer': [value['value']],
'weight': value['weight'],
})
default_answers = [{
'answer': [v],
'weight': 1,
} for v in record.values]
# Build our list of answers
answers = []
for pool_name in sorted(pools.keys()):
priority = 1
# Dynamic/health checked
current_pool_name = pool_name
while current_pool_name:
pool = pools[current_pool_name]
for answer in pool_answers[current_pool_name]:
answer = {
'answer': answer['answer'],
'meta': {
'priority': priority,
'note': self._encode_notes({
'from': current_pool_name,
}),
'weight': answer['weight'],
},
'region': pool_name, # the one we're answering
}
answers.append(answer)
current_pool_name = pool.data.get('fallback', None)
priority += 1
# Static/default
for answer in default_answers:
answer = {
'answer': answer['answer'],
'meta': {
'priority': priority,
'note': self._encode_notes({
'from': '--default--',
}),
'weight': 1,
},
'region': pool_name, # the one we're answering
}
answers.append(answer)
params.update({
'answers': answers,
'filters': self._DYNAMIC_FILTERS,
'regions': regions,
})
return params
elif hasattr(record, 'geo'):
# purposefully set non-geo answers to have an empty meta,
# so that we know we did this on purpose if/when troubleshooting
params['answers'] = [{"answer": [x], "meta": {}}
@@ -315,6 +471,9 @@ class Ns1Provider(BaseProvider):
{"filter": "select_first_n",
"config": {"N": 1}}
)
else:
params['answers'] = record.values
self.log.debug("params for A: %s", params)
return params