コード例 #1
0
    def __exit__(self, exc_type, exc_val, exc_tb):
        PDNSChangeTracker._active_change_trackers -= 1
        self._manage_signals('disconnect')

        if exc_type:
            # An exception occurred inside our context, exit db transaction and dismiss pdns changes
            self.transaction.__exit__(exc_type, exc_val, exc_tb)
            return

        # TODO introduce two phase commit protocol
        changes = self._compute_changes()
        axfr_required = set()
        for change in changes:
            try:
                change.pdns_do()
                change.api_do()
                if change.axfr_required:
                    axfr_required.add(change.domain_name)
            except Exception as e:
                self.transaction.__exit__(type(e), e, e.__traceback__)
                exc = ValueError(
                    f'For changes {list(map(str, changes))}, {type(e)} occurred during {change}: {str(e)}'
                )
                raise exc from e

        self.transaction.__exit__(None, None, None)

        for name in axfr_required:
            _pdns_put(NSMASTER, '/zones/%s/axfr-retrieve' % pdns_id(name))
        Domain.objects.filter(name__in=axfr_required).update(
            published=timezone.now())
コード例 #2
0
    def __exit__(self, exc_type, exc_val, exc_tb):
        self._manage_signals('disconnect')

        if exc_type:
            # An exception occurred inside our context, exit db transaction and dismiss pdns changes
            self.transaction.__exit__(exc_type, exc_val, exc_tb)
            return

        # TODO introduce two phase commit protocol
        changes = self._compute_changes()
        axfr_required = set()
        for change in changes:
            try:
                change.pdns_do()
                change.api_do()
                if change.axfr_required:
                    axfr_required.add(change.domain_name)
            except Exception as e:
                # TODO gather as much info as possible
                #  see if pdns and api are possibly in an inconsistent state
                self.transaction.__exit__(type(e), e, e.__traceback__)
                raise e

        self.transaction.__exit__(None, None, None)

        for name in axfr_required:
            _pdns_put(NSMASTER, '/zones/%s/axfr-retrieve' % pdns_id(name))
        Domain.objects.filter(name__in=axfr_required).update(
            published=timezone.now())
コード例 #3
0
ファイル: sync-to-pdns.py プロジェクト: unuseless/desec-stack
    def _sync_domain(domain):
        created = False

        # Create domain on pdns if it does not exist
        try:
            PDNSChangeTracker.CreateDomain(domain_name=domain.name).pdns_do()
        except PDNSException as e:
            # Domain already exists
            if e.response.status_code == 409:
                pass
            else:
                raise e
        else:
            created = True

        # modifications actually merged with additions in CreateUpdateDeleteRRSets
        modifications = {(rrset.type, rrset.subname)
                         for rrset in domain.rrset_set.all()}
        deletions = {(rrset['type'], rrset['subname'])
                     for rrset in pdns.get_rrset_datas(domain)} - modifications
        deletions.discard(('SOA', ''))  # do not remove SOA record

        # Update zone on nslord, propagate to nsmaster
        PDNSChangeTracker.CreateUpdateDeleteRRSets(domain.name, set(),
                                                   modifications,
                                                   deletions).pdns_do()
        pdns._pdns_put(
            pdns.NSMASTER,
            '/zones/{}/axfr-retrieve'.format(pdns.pdns_id(domain.name)))

        return created
コード例 #4
0
 def update_catalog(self, delete=False):
     return _pdns_patch(
         NSMASTER, '/zones/' + pdns_id(settings.CATALOG_ZONE), {
             'rrsets': [
                 construct_catalog_rrset(zone=self.domain_name,
                                         delete=delete)
             ]
         })
コード例 #5
0
 def update_catalog(self, delete=False):
     content = _pdns_patch(
         NSMASTER, '/zones/' + pdns_id(settings.CATALOG_ZONE), {
             'rrsets': [
                 construct_catalog_rrset(zone=self.domain_name,
                                         delete=delete)
             ]
         })
     metrics.get('desecapi_pdns_catalog_updated').inc()
     return content
コード例 #6
0
    def handle(self, *args, **options):
        catalog_zone_id = pdns_id(settings.CATALOG_ZONE)

        # Fetch zones from NSLORD
        response = _pdns_get(NSLORD, '/zones').json()
        zones = {zone['name'] for zone in response}

        # Retrieve catalog zone serial (later reused for recreating the catalog zone, for allow for smooth rollover)
        try:
            response = _pdns_get(NSMASTER, f'/zones/{catalog_zone_id}')
            serial = response.json()['serial']
        except PDNSException as e:
            if e.response.status_code == 404:
                serial = None
            else:
                raise e

        # Purge catalog zone if exists
        try:
            _pdns_delete(NSMASTER, f'/zones/{catalog_zone_id}')
        except PDNSException as e:
            if e.response.status_code != 404:
                raise e

        # Create new catalog zone
        rrsets = [
            construct_catalog_rrset(subname='', qtype='NS', rdata='invalid.'),  # as per the specification
            construct_catalog_rrset(subname='version', qtype='TXT', rdata='"2"'),  # as per the specification
            *(construct_catalog_rrset(zone=zone) for zone in zones)
        ]

        data = {
            'name': settings.CATALOG_ZONE + '.',
            'kind': 'MASTER',
            'dnssec': False,  # as per the specification
            'nameservers': [],
            'rrsets': rrsets,
        }

        if serial is not None:
            data['serial'] = serial + 1  # actually, pdns does increase this as well, but let's not rely on this

        _pdns_post(NSMASTER, '/zones?rrsets=false', data)
        print(f'Aligned catalog zone ({len(zones)} member zones).')
コード例 #7
0
 def domain_pdns_id(self):
     return pdns_id(self._domain_name)