mirror of
https://github.com/github/octodns.git
synced 2024-05-11 05:55:00 +00:00
Support PowerDNS 4.3.x
This commit is contained in:
@@ -19,12 +19,13 @@ class PowerDnsBaseProvider(BaseProvider):
|
||||
'PTR', 'SPF', 'SSHFP', 'SRV', 'TXT'))
|
||||
TIMEOUT = 5
|
||||
|
||||
def __init__(self, id, host, api_key, port=8081, scheme="http",
|
||||
timeout=TIMEOUT, *args, **kwargs):
|
||||
def __init__(self, id, host, api_key, soa_edit_api, port=8081,
|
||||
scheme="http", timeout=TIMEOUT, *args, **kwargs):
|
||||
super(PowerDnsBaseProvider, self).__init__(id, *args, **kwargs)
|
||||
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.soa_edit_api = soa_edit_api
|
||||
self.scheme = scheme
|
||||
self.timeout = timeout
|
||||
|
||||
@@ -178,10 +179,10 @@ class PowerDnsBaseProvider(BaseProvider):
|
||||
# Nicer error message for auth problems
|
||||
raise Exception('PowerDNS unauthorized host={}'
|
||||
.format(self.host))
|
||||
elif e.response.status_code == 422:
|
||||
# 422 means powerdns doesn't know anything about the requested
|
||||
# domain. We'll just ignore it here and leave the zone
|
||||
# untouched.
|
||||
elif e.response.status_code in (404, 422):
|
||||
# 404 or 422 means powerdns doesn't know anything about the
|
||||
# requested domain. We'll just ignore it here and leave the
|
||||
# zone untouched.
|
||||
pass
|
||||
else:
|
||||
# just re-throw
|
||||
@@ -338,23 +339,25 @@ class PowerDnsBaseProvider(BaseProvider):
|
||||
self.log.debug('_apply: patched')
|
||||
except HTTPError as e:
|
||||
error = self._get_error(e)
|
||||
if e.response.status_code != 422 or \
|
||||
not error.startswith('Could not find domain '):
|
||||
if e.response.status_code != 404 and \
|
||||
not (e.response.status_code == 422 and
|
||||
error.startswith('Could not find domain ')):
|
||||
self.log.error('_apply: status=%d, text=%s',
|
||||
e.response.status_code,
|
||||
e.response.text)
|
||||
raise
|
||||
self.log.info('_apply: creating zone=%s', desired.name)
|
||||
# 422 means powerdns doesn't know anything about the requested
|
||||
# domain. We'll try to create it with the correct records instead
|
||||
# of update. Hopefully all the mods are creates :-)
|
||||
# 404 or 422 means powerdns doesn't know anything about the
|
||||
# requested domain. We'll try to create it with the correct
|
||||
# records instead of update. Hopefully all the mods are
|
||||
# creates :-)
|
||||
data = {
|
||||
'name': desired.name,
|
||||
'kind': 'Master',
|
||||
'masters': [],
|
||||
'nameservers': [],
|
||||
'rrsets': mods,
|
||||
'soa_edit_api': 'INCEPTION-INCREMENT',
|
||||
'soa_edit_api': self.soa_edit_api,
|
||||
'serial': 0,
|
||||
}
|
||||
try:
|
||||
@@ -388,16 +391,25 @@ class PowerDnsProvider(PowerDnsBaseProvider):
|
||||
- 1.2.3.5.
|
||||
# The nameserver record TTL when managed, (optional, default 600)
|
||||
nameserver_ttl: 600
|
||||
# The SOA-EDIT-API value to set for newly created zones (optional)
|
||||
# Defaults to INCEPTION-INCREMENT. PowerDNS >=4.3.x users should use
|
||||
# 'DEFAULT' instead, as INCEPTION-INCREMENT is no longer a valid value.
|
||||
soa_edit_api: INCEPTION-INCREMENT
|
||||
'''
|
||||
|
||||
def __init__(self, id, host, api_key, port=8081, nameserver_values=None,
|
||||
nameserver_ttl=600, *args, **kwargs):
|
||||
nameserver_ttl=600, soa_edit_api='INCEPTION-INCREMENT',
|
||||
*args, **kwargs):
|
||||
self.log = logging.getLogger('PowerDnsProvider[{}]'.format(id))
|
||||
self.log.debug('__init__: id=%s, host=%s, port=%d, '
|
||||
'nameserver_values=%s, nameserver_ttl=%d',
|
||||
id, host, port, nameserver_values, nameserver_ttl)
|
||||
'nameserver_values=%s, nameserver_ttl=%d'
|
||||
'soa_edit_api=%s',
|
||||
id, host, port, nameserver_values, nameserver_ttl,
|
||||
soa_edit_api)
|
||||
super(PowerDnsProvider, self).__init__(id, host=host, api_key=api_key,
|
||||
port=port, *args, **kwargs)
|
||||
port=port,
|
||||
soa_edit_api=soa_edit_api,
|
||||
*args, **kwargs)
|
||||
|
||||
self.nameserver_values = nameserver_values
|
||||
self.nameserver_ttl = nameserver_ttl
|
||||
|
||||
@@ -64,7 +64,7 @@ class TestPowerDnsProvider(TestCase):
|
||||
provider.populate(zone)
|
||||
self.assertEquals(502, ctx.exception.response.status_code)
|
||||
|
||||
# Non-existent zone doesn't populate anything
|
||||
# Non-existent zone in PowerDNS <4.3.0 doesn't populate anything
|
||||
with requests_mock() as mock:
|
||||
mock.get(ANY, status_code=422,
|
||||
json={'error': "Could not find domain 'unit.tests.'"})
|
||||
@@ -73,6 +73,14 @@ class TestPowerDnsProvider(TestCase):
|
||||
provider.populate(zone)
|
||||
self.assertEquals(set(), zone.records)
|
||||
|
||||
# Non-existent zone in PowerDNS >=4.3.0 doesn't populate anything
|
||||
with requests_mock() as mock:
|
||||
mock.get(ANY, status_code=404, text='Not Found')
|
||||
|
||||
zone = Zone('unit.tests.', [])
|
||||
provider.populate(zone)
|
||||
self.assertEquals(set(), zone.records)
|
||||
|
||||
# The rest of this is messy/complicated b/c it's dealing with mocking
|
||||
|
||||
expected = Zone('unit.tests.', [])
|
||||
@@ -127,6 +135,19 @@ class TestPowerDnsProvider(TestCase):
|
||||
self.assertEquals(expected_n, provider.apply(plan))
|
||||
self.assertFalse(plan.exists)
|
||||
|
||||
with requests_mock() as mock:
|
||||
# get 404's, unknown zone
|
||||
mock.get(ANY, status_code=404, text='')
|
||||
# patch 404's, unknown zone
|
||||
mock.patch(ANY, status_code=404, text=dumps(not_found))
|
||||
# post 201, is response to the create with data
|
||||
mock.post(ANY, status_code=201, text=assert_rrsets_callback)
|
||||
|
||||
plan = provider.plan(expected)
|
||||
self.assertEquals(expected_n, len(plan.changes))
|
||||
self.assertEquals(expected_n, provider.apply(plan))
|
||||
self.assertFalse(plan.exists)
|
||||
|
||||
with requests_mock() as mock:
|
||||
# get 422's, unknown zone
|
||||
mock.get(ANY, status_code=422, text='')
|
||||
@@ -291,3 +312,22 @@ class TestPowerDnsProvider(TestCase):
|
||||
|
||||
plan = provider.plan(expected)
|
||||
self.assertEquals(1, len(plan.changes))
|
||||
|
||||
def test_soa_edit_api(self):
|
||||
provider = PowerDnsProvider('test', 'non.existent', 'api-key',
|
||||
soa_edit_api='DEFAULT')
|
||||
|
||||
def assert_soa_edit_api_callback(request, context):
|
||||
data = loads(request.body)
|
||||
self.assertEquals('DEFAULT', data['soa_edit_api'])
|
||||
return ''
|
||||
|
||||
with requests_mock() as mock:
|
||||
mock.get(ANY, status_code=404)
|
||||
mock.patch(ANY, status_code=404)
|
||||
mock.post(ANY, status_code=204, text=assert_soa_edit_api_callback)
|
||||
zone = Zone('unit.tests.', [])
|
||||
source = YamlProvider('test', join(dirname(__file__), 'config'))
|
||||
source.populate(zone)
|
||||
plan = provider.plan(zone)
|
||||
provider.apply(plan)
|
||||
|
||||
Reference in New Issue
Block a user