sync-from-pdns.py 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. from django.core.management import BaseCommand, CommandError
  2. from django.db import transaction
  3. from desecapi import pdns
  4. from desecapi.models import Domain, RRset, RR
  5. class Command(BaseCommand):
  6. help = 'Import authoritative data from pdns, making the local database consistent with pdns.'
  7. def add_arguments(self, parser):
  8. parser.add_argument('domain-name', nargs='*',
  9. help='Domain name to import. If omitted, will import all domains that are known locally.')
  10. def handle(self, *args, **options):
  11. domains = Domain.objects.all()
  12. if options['domain-name']:
  13. domains = domains.filter(name__in=options['domain-name'])
  14. domain_names = domains.values_list('name', flat=True)
  15. for domain_name in options['domain-name']:
  16. if domain_name not in domain_names:
  17. raise CommandError('{} is not a known domain'.format(domain_name))
  18. for domain in domains:
  19. self.stdout.write('%s ...' % domain.name, ending='')
  20. try:
  21. self._sync_domain(domain)
  22. self.stdout.write(' synced')
  23. except Exception as e:
  24. if str(e).startswith('Could not find domain ') \
  25. and domain.owner.locked:
  26. self.stdout.write(' skipped')
  27. else:
  28. self.stdout.write(' failed')
  29. msg = 'Error while processing {}: {}'.format(domain.name, e)
  30. raise CommandError(msg)
  31. @staticmethod
  32. @transaction.atomic
  33. def _sync_domain(domain):
  34. domain.rrset_set.all().delete()
  35. rrsets = []
  36. rrs = []
  37. for rrset_data in pdns.get_rrset_datas(domain):
  38. if rrset_data['type'] in RRset.RESTRICTED_TYPES:
  39. continue
  40. records = rrset_data.pop('records')
  41. rrset = RRset(**rrset_data)
  42. rrsets.append(rrset)
  43. rrs.extend([RR(rrset=rrset, content=record) for record in records])
  44. RRset.objects.bulk_create(rrsets)
  45. RR.objects.bulk_create(rrs)