Browse Source

Support PowerDNS 4.3.x

pull/564/head
Adam Mielke 6 years ago
parent
commit
f457f53938
2 changed files with 69 additions and 17 deletions
  1. +28
    -16
      octodns/provider/powerdns.py
  2. +41
    -1
      tests/test_octodns_provider_powerdns.py

+ 28
- 16
octodns/provider/powerdns.py View File

@ -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


+ 41
- 1
tests/test_octodns_provider_powerdns.py View File

@ -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)

Loading…
Cancel
Save