pdns.py 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. import requests
  2. import json
  3. from desecapi import settings
  4. headers = {
  5. 'User-Agent': 'desecapi',
  6. 'X-API-Key': settings.POWERDNS_API_TOKEN,
  7. }
  8. def normalize_hostname(name):
  9. if '/' in name or '?' in name:
  10. raise Exception('Invalid hostname ' + name)
  11. return name if name.endswith('.') else name + '.'
  12. def _pdns_post(url, body):
  13. r = requests.post(settings.POWERDNS_API + url, data=json.dumps(body), headers=headers)
  14. if r.status_code < 200 or r.status_code >= 300:
  15. raise Exception(r.text)
  16. return r
  17. def _pdns_patch(url, body):
  18. r = requests.patch(settings.POWERDNS_API + url, data=json.dumps(body), headers=headers)
  19. if r.status_code < 200 or r.status_code >= 300:
  20. raise Exception(r.text)
  21. return r
  22. def _pdns_get(url):
  23. r = requests.get(settings.POWERDNS_API + url, headers=headers)
  24. if (r.status_code < 200 or r.status_code >= 300) and r.status_code != 404:
  25. raise Exception(r.text)
  26. return r
  27. def _delete_or_replace(name, type, value):
  28. """
  29. Return pdns API json to either replace or delete a record, depending on value is empty or not.
  30. """
  31. if value != "":
  32. return \
  33. {
  34. "records": [
  35. {
  36. "type": type,
  37. "name": name,
  38. "disabled": False,
  39. "content": value,
  40. }
  41. ],
  42. "ttl": 60,
  43. "changetype": "REPLACE",
  44. "type": type,
  45. "name": name,
  46. }
  47. else:
  48. return \
  49. {
  50. "changetype": "DELETE",
  51. "type": type,
  52. "name": name
  53. }
  54. def create_native_zone(name):
  55. """
  56. Commands pdns to create a zone with the given name.
  57. """
  58. payload = {
  59. "name": normalize_hostname(name),
  60. "kind": "NATIVE",
  61. "masters": [],
  62. "nameservers": [
  63. "ns1.desec.io.",
  64. "ns2.desec.io."
  65. ]
  66. }
  67. _pdns_post('/zones', payload)
  68. def get_zone_exists(name):
  69. """
  70. Returns whether pdns knows a zone with the given name.
  71. """
  72. return _pdns_get('/zones/' + normalize_hostname(name)).status_code != 404
  73. def set_dyn_records(name, a, aaaa):
  74. """
  75. Commands pdns to set the A and AAAA record for the zone with the given name to the given record values.
  76. Only supports one A, one AAAA record.
  77. If a or aaaa is None, pdns will be commanded to delete the record.
  78. """
  79. name = normalize_hostname(name)
  80. _pdns_patch('/zones/' + name, {
  81. "rrsets": [
  82. _delete_or_replace(name, 'a', a),
  83. _delete_or_replace(name, 'aaaa', aaaa),
  84. ]
  85. })