123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- import requests
- import json
- import random
- from api import settings
- from desecapi.exceptions import PdnsException
- headers_nslord = {
- 'Accept': 'application/json',
- 'User-Agent': 'desecapi',
- 'X-API-Key': settings.NSLORD_PDNS_API_TOKEN,
- }
- headers_nsmaster = {
- 'User-Agent': 'desecapi',
- 'X-API-Key': settings.NSMASTER_PDNS_API_TOKEN,
- }
- def _pdns_delete_zone(domain):
- path = '/zones/' + domain.pdns_id
- # 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)
- 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:
- pass
- else:
- raise PdnsException(r1)
- # Delete from nsmaster as well
- r2 = requests.delete(settings.NSMASTER_PDNS_API + path, headers=headers_nsmaster)
- 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:
- pass
- else:
- raise PdnsException(r2)
- return (r1, r2)
- def _pdns_request(method, 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:
- raise PdnsException(detail='Payload too large', status=413)
- r = requests.request(method, settings.NSLORD_PDNS_API + path, data=data, headers=headers_nslord)
- 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_patch(path, body):
- return _pdns_request('patch', path, body)
- def _pdns_get(path):
- return _pdns_request('get', path, acceptable_range=range(200, 400))
- def _pdns_put(path):
- return _pdns_request('put', path, acceptable_range=range(200, 500))
- def create_zone(domain, nameservers):
- """
- Commands pdns to create a zone with the given name and nameservers.
- """
- name = domain.name
- if not name.endswith('.'):
- name += '.'
- 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)
- notify_zone(domain)
- def delete_zone(domain):
- """
- Commands pdns to delete a zone with the given name.
- """
- return _pdns_delete_zone(domain)
- def get_keys(domain):
- """
- Retrieves a dict representation of the DNSSEC key information
- """
- r = _pdns_get('/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']]
- def get_zone(domain):
- """
- Retrieves a dict representation of the zone from pdns
- """
- r = _pdns_get('/zones/' + domain.pdns_id)
- return r.json()
- def get_rrset_datas(domain):
- """
- Retrieves a dict representation of the RRsets in a given zone
- """
- return [{'domain': domain,
- 'subname': rrset['name'][:-(len(domain.name) + 2)],
- 'type': rrset['type'],
- 'records': [record['content'] for record in rrset['records']],
- 'ttl': rrset['ttl']}
- for rrset in get_zone(domain)['rrsets']]
- def set_rrsets(domain, rrsets, notify=True):
- data = {'rrsets':
- [{'name': rrset.name, 'type': rrset.type, 'ttl': rrset.ttl,
- 'changetype': 'REPLACE',
- 'records': [{'content': record.content, 'disabled': False}
- for record in rrset.records.all()]
- }
- for rrset in rrsets]
- }
- _pdns_patch('/zones/' + domain.pdns_id, data)
- if notify:
- notify_zone(domain)
- def notify_zone(domain):
- """
- Commands pdns to notify the zone to the pdns slaves.
- """
- _pdns_put('/zones/%s/notify' % domain.pdns_id)
|