|
@@ -1,20 +1,33 @@
|
|
|
import json
|
|
|
import random
|
|
|
+import socket
|
|
|
|
|
|
import requests
|
|
|
|
|
|
-from api import settings
|
|
|
+from api import settings as api_settings
|
|
|
from desecapi.exceptions import PdnsException
|
|
|
|
|
|
-headers_nslord = {
|
|
|
- 'Accept': 'application/json',
|
|
|
- 'User-Agent': 'desecapi',
|
|
|
- 'X-API-Key': settings.NSLORD_PDNS_API_TOKEN,
|
|
|
-}
|
|
|
+NSLORD = object()
|
|
|
+NSMASTER = object()
|
|
|
+
|
|
|
+settings = {
|
|
|
+ NSLORD: {
|
|
|
+ 'base_url': api_settings.NSLORD_PDNS_API,
|
|
|
+ 'headers': {
|
|
|
+ 'Accept': 'application/json',
|
|
|
+ 'User-Agent': 'desecapi',
|
|
|
+ 'X-API-Key': api_settings.NSLORD_PDNS_API_TOKEN,
|
|
|
+ }
|
|
|
+ },
|
|
|
+ NSMASTER: {
|
|
|
+ 'base_url': api_settings.NSMASTER_PDNS_API,
|
|
|
+ 'headers': {
|
|
|
+ 'Accept': 'application/json',
|
|
|
+ 'User-Agent': 'desecapi',
|
|
|
+ 'X-API-Key': api_settings.NSMASTER_PDNS_API_TOKEN,
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
-headers_nsmaster = {
|
|
|
- 'User-Agent': 'desecapi',
|
|
|
- 'X-API-Key': settings.NSMASTER_PDNS_API_TOKEN,
|
|
|
}
|
|
|
|
|
|
|
|
@@ -24,7 +37,7 @@ def _pdns_delete_zone(domain):
|
|
|
# We first delete the zone from nslord, the main authoritative source of our DNS data.
|
|
|
# However, we do not want to wait for the zone to expire on the slave ("nsmaster").
|
|
|
# We thus issue a second delete request on nsmaster to delete the zone there immediately.
|
|
|
- r1 = requests.delete(settings.NSLORD_PDNS_API + path, headers=headers_nslord)
|
|
|
+ r1 = requests.delete(settings[NSLORD]['base_url'] + path, headers=settings[NSLORD]['headers'])
|
|
|
if r1.status_code < 200 or r1.status_code >= 300:
|
|
|
# Deletion technically does not fail if the zone didn't exist in the first place
|
|
|
if r1.status_code == 422 and 'Could not find domain' in r1.text:
|
|
@@ -33,7 +46,7 @@ def _pdns_delete_zone(domain):
|
|
|
raise PdnsException(r1)
|
|
|
|
|
|
# Delete from nsmaster as well
|
|
|
- r2 = requests.delete(settings.NSMASTER_PDNS_API + path, headers=headers_nsmaster)
|
|
|
+ r2 = requests.delete(settings[NSMASTER]['base_url'] + path, headers=settings[NSMASTER]['headers'])
|
|
|
if r2.status_code < 200 or r2.status_code >= 300:
|
|
|
# Deletion technically does not fail if the zone didn't exist in the first place
|
|
|
if r2.status_code == 422 and 'Could not find domain' in r2.text:
|
|
@@ -44,32 +57,32 @@ def _pdns_delete_zone(domain):
|
|
|
return r1, r2
|
|
|
|
|
|
|
|
|
-def _pdns_request(method, path, body=None, acceptable_range=range(200, 300)):
|
|
|
+def _pdns_request(method, *, server, path, body=None, acceptable_range=range(200, 300)):
|
|
|
data = json.dumps(body) if body else None
|
|
|
- if data is not None and len(data) > settings.PDNS_MAX_BODY_SIZE:
|
|
|
+ if data is not None and len(data) > api_settings.PDNS_MAX_BODY_SIZE:
|
|
|
raise PdnsException(detail='Payload too large', status=413)
|
|
|
|
|
|
- r = requests.request(method, settings.NSLORD_PDNS_API + path, data=data, headers=headers_nslord)
|
|
|
+ r = requests.request(method, settings[server]['base_url'] + path, data=data, headers=settings[server]['headers'])
|
|
|
if r.status_code not in acceptable_range:
|
|
|
raise PdnsException(r)
|
|
|
|
|
|
return r
|
|
|
|
|
|
|
|
|
-def _pdns_post(path, body):
|
|
|
- return _pdns_request('post', path, body)
|
|
|
+def _pdns_post(server, path, body):
|
|
|
+ return _pdns_request('post', server=server, path=path, body=body)
|
|
|
|
|
|
|
|
|
-def _pdns_patch(path, body):
|
|
|
- return _pdns_request('patch', path, body)
|
|
|
+def _pdns_patch(server, path, body):
|
|
|
+ return _pdns_request('patch', server=server, path=path, body=body)
|
|
|
|
|
|
|
|
|
-def _pdns_get(path):
|
|
|
- return _pdns_request('get', path, acceptable_range=range(200, 400))
|
|
|
+def _pdns_get(server, path):
|
|
|
+ return _pdns_request('get', server=server, path=path, acceptable_range=range(200, 400))
|
|
|
|
|
|
|
|
|
-def _pdns_put(path):
|
|
|
- return _pdns_request('put', path, acceptable_range=range(200, 500))
|
|
|
+def _pdns_put(server, path):
|
|
|
+ return _pdns_request('put', server=server, path=path, acceptable_range=range(200, 500))
|
|
|
|
|
|
|
|
|
def create_zone(domain, nameservers):
|
|
@@ -83,9 +96,12 @@ def create_zone(domain, nameservers):
|
|
|
salt = '%016x' % random.randrange(16**16)
|
|
|
payload = {'name': name, 'kind': 'MASTER', 'dnssec': True,
|
|
|
'nsec3param': '1 0 127 %s' % salt, 'nameservers': nameservers}
|
|
|
- _pdns_post('/zones', payload)
|
|
|
+ _pdns_post(NSLORD, '/zones', payload)
|
|
|
+
|
|
|
+ payload = {'name': name, 'kind': 'SLAVE', 'masters': [socket.gethostbyname('nslord')]}
|
|
|
+ _pdns_post(NSMASTER, '/zones', payload)
|
|
|
|
|
|
- notify_zone(domain)
|
|
|
+ axfr_zone(domain)
|
|
|
|
|
|
|
|
|
def delete_zone(domain):
|
|
@@ -99,7 +115,7 @@ def get_keys(domain):
|
|
|
"""
|
|
|
Retrieves a dict representation of the DNSSEC key information
|
|
|
"""
|
|
|
- r = _pdns_get('/zones/%s/cryptokeys' % domain.pdns_id)
|
|
|
+ r = _pdns_get(NSLORD, '/zones/%s/cryptokeys' % domain.pdns_id)
|
|
|
return [{k: key[k] for k in ('dnskey', 'ds', 'flags', 'keytype')}
|
|
|
for key in r.json()
|
|
|
if key['active'] and key['keytype'] in ['csk', 'ksk']]
|
|
@@ -109,7 +125,7 @@ def get_zone(domain):
|
|
|
"""
|
|
|
Retrieves a dict representation of the zone from pdns
|
|
|
"""
|
|
|
- r = _pdns_get('/zones/' + domain.pdns_id)
|
|
|
+ r = _pdns_get(NSLORD, '/zones/' + domain.pdns_id)
|
|
|
|
|
|
return r.json()
|
|
|
|
|
@@ -126,7 +142,7 @@ def get_rrset_datas(domain):
|
|
|
for rrset in get_zone(domain)['rrsets']]
|
|
|
|
|
|
|
|
|
-def set_rrsets(domain, rrsets, notify=True):
|
|
|
+def set_rrsets(domain, rrsets, axfr=True):
|
|
|
data = {
|
|
|
'rrsets':
|
|
|
[
|
|
@@ -141,14 +157,14 @@ def set_rrsets(domain, rrsets, notify=True):
|
|
|
for rrset in rrsets
|
|
|
]
|
|
|
}
|
|
|
- _pdns_patch('/zones/' + domain.pdns_id, data)
|
|
|
+ _pdns_patch(NSLORD, '/zones/' + domain.pdns_id, data)
|
|
|
|
|
|
- if notify:
|
|
|
- notify_zone(domain)
|
|
|
+ if axfr:
|
|
|
+ axfr_zone(domain)
|
|
|
|
|
|
|
|
|
-def notify_zone(domain):
|
|
|
+def axfr_zone(domain):
|
|
|
"""
|
|
|
- Commands pdns to notify the zone to the pdns slaves.
|
|
|
+ Commands nsmaster to retrieve the zone from nslord.
|
|
|
"""
|
|
|
- _pdns_put('/zones/%s/notify' % domain.pdns_id)
|
|
|
+ _pdns_put(NSMASTER, '/zones/%s/axfr-retrieve' % domain.pdns_id)
|