mirror of
https://github.com/github/octodns.git
synced 2024-05-11 05:55:00 +00:00
Add support for dynamic CNAME records in NS1
This commit is contained in:
@@ -588,16 +588,22 @@ class Ns1Provider(BaseProvider):
|
|||||||
rules = list(rules.values())
|
rules = list(rules.values())
|
||||||
rules.sort(key=lambda r: (r['_order'], r['pool']))
|
rules.sort(key=lambda r: (r['_order'], r['pool']))
|
||||||
|
|
||||||
return {
|
data = {
|
||||||
'dynamic': {
|
'dynamic': {
|
||||||
'pools': pools,
|
'pools': pools,
|
||||||
'rules': rules,
|
'rules': rules,
|
||||||
},
|
},
|
||||||
'ttl': record['ttl'],
|
'ttl': record['ttl'],
|
||||||
'type': _type,
|
'type': _type,
|
||||||
'values': sorted(default),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if _type == 'CNAME':
|
||||||
|
data['value'] = default[0]
|
||||||
|
else:
|
||||||
|
data['values'] = default
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
def _data_for_A(self, _type, record):
|
def _data_for_A(self, _type, record):
|
||||||
if record.get('tier', 1) > 1:
|
if record.get('tier', 1) > 1:
|
||||||
# Advanced record, see if it's first answer has a note
|
# Advanced record, see if it's first answer has a note
|
||||||
@@ -646,6 +652,10 @@ class Ns1Provider(BaseProvider):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def _data_for_CNAME(self, _type, record):
|
def _data_for_CNAME(self, _type, record):
|
||||||
|
if record.get('tier', 1) > 1:
|
||||||
|
# Advanced dynamic record
|
||||||
|
return self._data_for_dynamic_A(_type, record)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
value = record['short_answers'][0]
|
value = record['short_answers'][0]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
@@ -1114,10 +1124,14 @@ class Ns1Provider(BaseProvider):
|
|||||||
'feed_id': feed_id,
|
'feed_id': feed_id,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if record._type == 'CNAME':
|
||||||
|
default_values = [record.value]
|
||||||
|
else:
|
||||||
|
default_values = record.values
|
||||||
default_answers = [{
|
default_answers = [{
|
||||||
'answer': [v],
|
'answer': [v],
|
||||||
'weight': 1,
|
'weight': 1,
|
||||||
} for v in record.values]
|
} for v in default_values]
|
||||||
|
|
||||||
# Build our list of answers
|
# Build our list of answers
|
||||||
# The regions dictionary built above already has the required pool
|
# The regions dictionary built above already has the required pool
|
||||||
@@ -1171,8 +1185,10 @@ class Ns1Provider(BaseProvider):
|
|||||||
values = [(v.flags, v.tag, v.value) for v in record.values]
|
values = [(v.flags, v.tag, v.value) for v in record.values]
|
||||||
return {'answers': values, 'ttl': record.ttl}, None
|
return {'answers': values, 'ttl': record.ttl}, None
|
||||||
|
|
||||||
# TODO: dynamic CNAME support
|
|
||||||
def _params_for_CNAME(self, record):
|
def _params_for_CNAME(self, record):
|
||||||
|
if getattr(record, 'dynamic', False):
|
||||||
|
return self._params_for_dynamic_A(record)
|
||||||
|
|
||||||
return {'answers': [record.value], 'ttl': record.ttl}, None
|
return {'answers': [record.value], 'ttl': record.ttl}, None
|
||||||
|
|
||||||
_params_for_ALIAS = _params_for_CNAME
|
_params_for_ALIAS = _params_for_CNAME
|
||||||
|
|||||||
@@ -1270,6 +1270,63 @@ class TestNs1ProviderDynamic(TestCase):
|
|||||||
params, _ = provider._params_for_geo_A(record)
|
params, _ = provider._params_for_geo_A(record)
|
||||||
self.assertEquals([], params['filters'])
|
self.assertEquals([], params['filters'])
|
||||||
|
|
||||||
|
@patch('octodns.provider.ns1.Ns1Provider._monitor_sync')
|
||||||
|
@patch('octodns.provider.ns1.Ns1Provider._monitors_for')
|
||||||
|
def test_params_for_dynamic_CNAME(self, monitors_for_mock,
|
||||||
|
monitor_sync_mock):
|
||||||
|
provider = Ns1Provider('test', 'api-key')
|
||||||
|
|
||||||
|
# pre-fill caches to avoid extranious calls (things we're testing
|
||||||
|
# elsewhere)
|
||||||
|
provider._client._datasource_id = 'foo'
|
||||||
|
provider._client._feeds_for_monitors = {
|
||||||
|
'mon-id': 'feed-id',
|
||||||
|
}
|
||||||
|
|
||||||
|
# provider._params_for_A() calls provider._monitors_for() and
|
||||||
|
# provider._monitor_sync(). Mock their return values so that we don't
|
||||||
|
# make NS1 API calls during tests
|
||||||
|
monitors_for_mock.reset_mock()
|
||||||
|
monitor_sync_mock.reset_mock()
|
||||||
|
monitors_for_mock.side_effect = [{
|
||||||
|
'iad.unit.tests.': 'mid-1',
|
||||||
|
}]
|
||||||
|
monitor_sync_mock.side_effect = [
|
||||||
|
('mid-1', 'fid-1'),
|
||||||
|
]
|
||||||
|
|
||||||
|
record = Record.new(self.zone, 'foo', {
|
||||||
|
'dynamic': {
|
||||||
|
'pools': {
|
||||||
|
'iad': {
|
||||||
|
'values': [{
|
||||||
|
'value': 'iad.unit.tests.',
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'rules': [{
|
||||||
|
'pool': 'iad',
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
'octodns': {
|
||||||
|
'healthcheck': {
|
||||||
|
'host': 'send.me',
|
||||||
|
'path': '/_ping',
|
||||||
|
'port': 80,
|
||||||
|
'protocol': 'HTTP',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'ttl': 32,
|
||||||
|
'type': 'CNAME',
|
||||||
|
'value': 'value.unit.tests.',
|
||||||
|
'meta': {},
|
||||||
|
})
|
||||||
|
ret, _ = provider._params_for_CNAME(record)
|
||||||
|
|
||||||
|
# Check if the default value was correctly read and populated
|
||||||
|
# All other dynamic record test cases are covered by dynamic_A tests
|
||||||
|
self.assertEquals(ret['answers'][1]['answer'][0], 'value.unit.tests.')
|
||||||
|
|
||||||
def test_data_for_dynamic_A(self):
|
def test_data_for_dynamic_A(self):
|
||||||
provider = Ns1Provider('test', 'api-key')
|
provider = Ns1Provider('test', 'api-key')
|
||||||
|
|
||||||
@@ -1471,6 +1528,67 @@ class TestNs1ProviderDynamic(TestCase):
|
|||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
'OC-{}'.format(c) in data4['dynamic']['rules'][0]['geos'])
|
'OC-{}'.format(c) in data4['dynamic']['rules'][0]['geos'])
|
||||||
|
|
||||||
|
def test_data_for_dynamic_CNAME(self):
|
||||||
|
provider = Ns1Provider('test', 'api-key')
|
||||||
|
|
||||||
|
# Test out a small setup that just covers default value validation
|
||||||
|
# Everything else is same as dynamic A whose tests will cover all
|
||||||
|
# other options and test cases
|
||||||
|
# Not testing for geo/region specific cases
|
||||||
|
filters = provider._get_updated_filter_chain(False, False)
|
||||||
|
catchall_pool_name = 'iad__catchall'
|
||||||
|
ns1_record = {
|
||||||
|
'answers': [{
|
||||||
|
'answer': ['2.3.4.5.unit.tests.'],
|
||||||
|
'meta': {
|
||||||
|
'priority': 1,
|
||||||
|
'weight': 12,
|
||||||
|
'note': 'from:{}'.format(catchall_pool_name),
|
||||||
|
},
|
||||||
|
'region': catchall_pool_name,
|
||||||
|
}, {
|
||||||
|
'answer': ['1.2.3.4.unit.tests.'],
|
||||||
|
'meta': {
|
||||||
|
'priority': 2,
|
||||||
|
'note': 'from:--default--',
|
||||||
|
},
|
||||||
|
'region': catchall_pool_name,
|
||||||
|
}],
|
||||||
|
'domain': 'foo.unit.tests',
|
||||||
|
'filters': filters,
|
||||||
|
'regions': {
|
||||||
|
catchall_pool_name: {
|
||||||
|
'meta': {
|
||||||
|
'note': 'rule-order:1',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'tier': 3,
|
||||||
|
'ttl': 42,
|
||||||
|
'type': 'CNAME',
|
||||||
|
}
|
||||||
|
data = provider._data_for_CNAME('CNAME', ns1_record)
|
||||||
|
self.assertEquals({
|
||||||
|
'dynamic': {
|
||||||
|
'pools': {
|
||||||
|
'iad': {
|
||||||
|
'fallback': None,
|
||||||
|
'values': [{
|
||||||
|
'value': '2.3.4.5.unit.tests.',
|
||||||
|
'weight': 12,
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'rules': [{
|
||||||
|
'_order': '1',
|
||||||
|
'pool': 'iad',
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
'ttl': 42,
|
||||||
|
'type': 'CNAME',
|
||||||
|
'value': '1.2.3.4.unit.tests.',
|
||||||
|
}, data)
|
||||||
|
|
||||||
@patch('ns1.rest.records.Records.retrieve')
|
@patch('ns1.rest.records.Records.retrieve')
|
||||||
@patch('ns1.rest.zones.Zones.retrieve')
|
@patch('ns1.rest.zones.Zones.retrieve')
|
||||||
@patch('octodns.provider.ns1.Ns1Provider._monitors_for')
|
@patch('octodns.provider.ns1.Ns1Provider._monitors_for')
|
||||||
|
|||||||
Reference in New Issue
Block a user