def test_subname_validity(self): for subname in ['aEroport', 'AEROPORT', 'aƩroport']: with self.assertRaises(ValidationError): RRset(domain=self.my_domain, subname=subname, ttl=60, type='A').save() RRset(domain=self.my_domain, subname='aeroport', ttl=60, type='A').save()
def pdns_do(self): data = { 'rrsets': [ { 'name': RRset.construct_name(subname, self._domain_name), 'type': type_, 'ttl': 1, # some meaningless integer required by pdns's syntax 'changetype': 'REPLACE', # don't use "DELETE" due to desec-stack#220, PowerDNS/pdns#7501 'records': [] } for type_, subname in self._deletions ] + [ { 'name': RRset.construct_name(subname, self._domain_name), 'type': type_, 'ttl': RRset.objects.values_list('ttl', flat=True).get(domain__name=self._domain_name, type=type_, subname=subname), 'changetype': 'REPLACE', 'records': [ {'content': rr.content, 'disabled': False} for rr in RR.objects.filter( rrset__domain__name=self._domain_name, rrset__type=type_, rrset__subname=subname) ] } for type_, subname in (self._additions | self._modifications) - self._deletions ] } if data['rrsets']: _pdns_patch(NSLORD, '/zones/' + self.domain_pdns_id, data)
def create_rr_set(cls, domain, records, **kwargs): if isinstance(domain, str): domain = Domain.objects.get(name=domain) domain.save() rr_set = RRset(domain=domain, **kwargs) rr_set.save() for r in records: RR(content=r, rrset=rr_set).save() return rr_set
def api_do(self): rr_set = RRset( domain=Domain.objects.get(name=self.domain_name), type='NS', subname='', ttl=settings.DEFAULT_NS_TTL, ) rr_set.save() rrs = [RR(rrset=rr_set, content=ns) for ns in settings.DEFAULT_NS] RR.objects.bulk_create(rrs) # One INSERT
def update(self, instance: RRset, validated_data): rrs_data = validated_data.pop('records', None) if rrs_data is not None: self._set_all_record_contents(instance, rrs_data) ttl = validated_data.pop('ttl', None) if ttl and instance.ttl != ttl: instance.ttl = ttl instance.save() return instance
def _set_all_record_contents(rrset: models.RRset, rrs): """ Updates this RR set's resource records, discarding any old values. :param rrset: the RRset at which we overwrite all RRs :param rrs: list of RR representations """ record_contents = [rr['content'] for rr in rrs] try: rrset.save_records(record_contents) except django.core.exceptions.ValidationError as e: raise serializers.ValidationError(e.messages, code='record-content')
def _create_rr_sets(cls, data, domain): rr_sets = [] rrs = {} for (type_, subname, ttl), rr_contents in data.items(): rr_set = RRset(domain=domain, subname=subname, type=type_, ttl=ttl) rr_sets.append(rr_set) rrs[(type_, subname)] = this_rrs = [] rr_set.save() for content in rr_contents: rr = RR(content=content, rrset=rr_set) this_rrs.append(rr) rr.save() return rr_sets, rrs
def update(self, instance: models.RRset, validated_data): rrs_data = validated_data.pop('records', None) if rrs_data is not None: self._set_all_record_contents(instance, rrs_data) ttl = validated_data.pop('ttl', None) if ttl and instance.ttl != ttl: instance.ttl = ttl instance.save() # also updates instance.touched else: # Update instance.touched without triggering post-save signal (no pdns action required) models.RRset.objects.filter(pk=instance.pk).update(touched=timezone.now()) return instance
def _sync_domain(domain): domain.rrset_set.all().delete() rrsets = [] rrs = [] for rrset_data in pdns.get_rrset_datas(domain): if rrset_data['type'] in RR_SET_TYPES_AUTOMATIC: continue records = rrset_data.pop('records') rrset = RRset(**rrset_data) rrsets.append(rrset) rrs.extend([RR(rrset=rrset, content=record) for record in records]) RRset.objects.bulk_create(rrsets) RR.objects.bulk_create(rrs)
def test_retrieve_my_rr_sets_pagination(self): def convert_links(links): mapping = {} for link in links.split(', '): _url, label = link.split('; ') label = re.search('rel="(.*)"', label).group(1) _url = _url[1:-1] assert label not in mapping mapping[label] = _url return mapping def assertPaginationResponse(response, expected_length, expected_directional_links=[]): self.assertStatus(response, status.HTTP_200_OK) self.assertEqual(len(response.data), expected_length) _links = convert_links(response['Link']) self.assertEqual(len(_links), len(expected_directional_links) + 1) # directional links, plus "first" self.assertTrue(_links['first'].endswith('/?cursor=')) for directional_link in expected_directional_links: self.assertEqual(_links['first'].find('/?cursor='), _links[directional_link].find('/?cursor=')) self.assertTrue(len(_links[directional_link]) > len(_links['first'])) # Prepare extra records so that we get three pages (total: n + 1) n = int(settings.REST_FRAMEWORK['PAGE_SIZE'] * 2.5) RRset.objects.bulk_create( [RRset(domain=self.my_domain, subname=str(i), ttl=123, type='A') for i in range(n)] ) # No pagination response = self.client.get_rr_sets(self.my_domain.name) self.assertStatus(response, status.HTTP_400_BAD_REQUEST) self.assertEqual(response.data['detail'], f'Pagination required. You can query up to {settings.REST_FRAMEWORK["PAGE_SIZE"]} items at a time ({n+1} total). ' 'Please use the `first` page link (see Link header).') links = convert_links(response['Link']) self.assertEqual(len(links), 1) self.assertTrue(links['first'].endswith('/?cursor=')) # First page url = links['first'] response = self.client.get(url) assertPaginationResponse(response, settings.REST_FRAMEWORK['PAGE_SIZE'], ['next']) # Next url = convert_links(response['Link'])['next'] response = self.client.get(url) assertPaginationResponse(response, settings.REST_FRAMEWORK['PAGE_SIZE'], ['next', 'prev']) data_next = response.data.copy() # Next-next (last) page url = convert_links(response['Link'])['next'] response = self.client.get(url) assertPaginationResponse(response, n/5 + 1, ['prev']) # Prev url = convert_links(response['Link'])['prev'] response = self.client.get(url) assertPaginationResponse(response, settings.REST_FRAMEWORK['PAGE_SIZE'], ['next', 'prev']) # Make sure that one step forward equals two steps forward and one step back self.assertEqual(response.data, data_next)
def test_rrset_does_not_exist_exception(self): tracker = PDNSChangeTracker() tracker.__enter__() tracker._rr_set_updated(RRset(domain=self.empty_domain, subname='', type='A')) with self.assertRaises(ValueError): tracker.__exit__(None, None, None)