Improve DNS table models

This commit adds Meta information and __str__ methods  to all DNS table
models. The new methods are now covered with new tests. The new
constants DNS_DOMAIN_METADATA_KINDS and DNS_TSIG_KEY_ALGORITHMS are
defined and used in the DNSDomainMetadata and DNSTSIGKey models. A
matching database schema migration is added.

Addresses #17
This commit is contained in:
Jan Dittberner 2015-11-07 16:10:38 +00:00
parent 1df2534cf3
commit c058cc7b1d
3 changed files with 193 additions and 7 deletions

View File

@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('domains', '0003_auto_20151105_2133'),
]
operations = [
migrations.AlterModelOptions(
name='dnscomment',
options={'verbose_name': 'DNS comment', 'verbose_name_plural': 'DNS comments'},
),
migrations.AlterModelOptions(
name='dnscryptokey',
options={'verbose_name': 'DNS crypto key', 'verbose_name_plural': 'DNS crypto keys'},
),
migrations.AlterModelOptions(
name='dnsdomainmetadata',
options={'verbose_name': 'DNS domain metadata item', 'verbose_name_plural': 'DNS domain metadata items'},
),
migrations.AlterModelOptions(
name='dnssupermaster',
options={'verbose_name': 'DNS supermaster', 'verbose_name_plural': 'DNS supermasters'},
),
migrations.AlterModelOptions(
name='dnstsigkey',
options={'verbose_name': 'DNS TSIG key', 'verbose_name_plural': 'DNS TSIG keys'},
),
migrations.AlterField(
model_name='dnsdomainmetadata',
name='kind',
field=models.CharField(max_length=32, choices=[('ALLOW-DNSUPDATE-FROM', 'ALLOW-DNSUPDATE-FROM'), ('ALSO-NOTIFY', 'ALSO-NOTIFY'), ('AXFR-MASTER-TSIG', 'AXFR-MASTER-TSIG'), ('AXFR-SOURCE', 'AXFR-SOURCE'), ('FORWARD-DNSUPDATE', 'FORWARD-DNSUPDATE'), ('GSS-ACCEPTOR-PRINCIPAL', 'GSS-ACCEPTOR-PRINCIPAL'), ('GSS-ALLOW-AXFR-PRINCIPAL', 'GSS-ALLOW-AXFR-PRINCIPAL'), ('LUA-AXFR-SCRIPT', 'LUA-AXFR-SCRIPT'), ('NSEC3NARROW', 'NSEC3NARROW'), ('NSEC3PARAM', 'NSEC3PARAM'), ('PRESIGNED', 'PRESIGNED'), ('PUBLISH_CDNSKEY', 'PUBLISH_CDNSKEY'), ('PUBLISH_CDS', 'PUBLISH_CDS'), ('SOA-EDIT', 'SOA-EDIT'), ('SOA-EDIT-DNSUPDATE', 'SOA-EDIT-DNSUPDATE'), ('TSIG-ALLOW-AXFR', 'TSIG-ALLOW-AXFR'), ('TSIG-ALLOW-DNSUPDATE', 'TSIG-ALLOW-DNSUPDATE')]),
),
migrations.AlterField(
model_name='dnstsigkey',
name='algorithm',
field=models.CharField(max_length=50, choices=[('hmac-md5', 'HMAC MD5'), ('hmac-sha1', 'HMAC SHA1'), ('hmac-sha224', 'HMAC SHA224'), ('hmac-sha256', 'HMAC SHA256'), ('hmac-sha384', 'HMAC SHA384'), ('hmac-sha512', 'HMAC SHA512')]),
),
]

View File

@ -19,6 +19,36 @@ DNS_DOMAIN_TYPES = Choices(
('NATIVE', _('Native')),
)
# see https://doc.powerdns.com/md/authoritative/domainmetadata/
DNS_DOMAIN_METADATA_KINDS = Choices(
'ALLOW-DNSUPDATE-FROM',
'ALSO-NOTIFY',
'AXFR-MASTER-TSIG',
'AXFR-SOURCE',
'FORWARD-DNSUPDATE',
'GSS-ACCEPTOR-PRINCIPAL',
'GSS-ALLOW-AXFR-PRINCIPAL',
'LUA-AXFR-SCRIPT',
'NSEC3NARROW',
'NSEC3PARAM',
'PRESIGNED',
'PUBLISH_CDNSKEY',
'PUBLISH_CDS',
'SOA-EDIT',
'SOA-EDIT-DNSUPDATE',
'TSIG-ALLOW-AXFR',
'TSIG-ALLOW-DNSUPDATE',
)
DNS_TSIG_KEY_ALGORITHMS = Choices(
('hmac-md5', _('HMAC MD5')),
('hmac-sha1', _('HMAC SHA1')),
('hmac-sha224', _('HMAC SHA224')),
('hmac-sha256', _('HMAC SHA256')),
('hmac-sha384', _('HMAC SHA384')),
('hmac-sha512', _('HMAC SHA512')),
)
@python_2_unicode_compatible
class DomainBase(TimeStampedModel):
@ -144,6 +174,7 @@ class DNSDomain(DomainBase):
return self.domain
@python_2_unicode_compatible
class DNSRecord(models.Model):
"""
This model represents a DNS record. The model is similar to the record
@ -195,7 +226,12 @@ class DNSRecord(models.Model):
['name', 'recordtype']
]
def __str__(self):
return "{name} IN {type} {content}".format(
name=self.name, type=self.recordtype, content=self.content)
@python_2_unicode_compatible
class DNSSupermaster(models.Model):
"""
This model represents the supermasters table in the PowerDNS schema
@ -217,15 +253,24 @@ class DNSSupermaster(models.Model):
settings.AUTH_USER_MODEL, verbose_name=_('customer'))
class Meta:
verbose_name = _('DNS supermaster')
verbose_name_plural = _('DNS supermasters')
unique_together = (
('ip', 'nameserver')
)
def __str__(self):
return "{ip} {nameserver}".format(
ip=self.ip, nameserver=self.nameserver)
@python_2_unicode_compatible
class DNSComment(models.Model):
"""
This model represents the comments table in the PowerDNS schema specified
in https://doc.powerdns.com/md/authoritative/backend-generic-mypgsql/.
in https://doc.powerdns.com/md/authoritative/backend-generic-mypgsql/. The
comments table is used to store user comments related to individual DNS
records.
CREATE TABLE comments (
id SERIAL PRIMARY KEY,
@ -257,17 +302,26 @@ class DNSComment(models.Model):
# check constraint is added via RunSQL in migration
class Meta:
verbose_name = _('DNS comment')
verbose_name_plural = _('DNS comments')
index_together = [
['name', 'commenttype'],
['domain', 'modified_at']
]
def __str__(self):
return "{name} IN {type}: {comment}".format(
name=self.name, type=self.commenttype, comment=self.comment)
@python_2_unicode_compatible
class DNSDomainMetadata(models.Model):
"""
This model represents the domainmetadata table in the PowerDNS schema
specified in
https://doc.powerdns.com/md/authoritative/backend-generic-mypgsql/.
The domainmetadata table is used to store domain meta data as described in
https://doc.powerdns.com/md/authoritative/domainmetadata/.
CREATE TABLE domainmetadata (
id SERIAL PRIMARY KEY,
@ -279,10 +333,19 @@ class DNSDomainMetadata(models.Model):
CREATE INDEX domainidmetaindex ON domainmetadata(domain_id);
"""
domain = models.ForeignKey('DNSDomain')
kind = models.CharField(max_length=32)
kind = models.CharField(max_length=32, choices=DNS_DOMAIN_METADATA_KINDS)
content = models.TextField()
class Meta:
verbose_name = _('DNS domain metadata item')
verbose_name_plural = _('DNS domain metadata items')
def __str__(self):
return "{domain} {kind} {content}".format(
domain=self.domain.domain, kind=self.kind, content=self.content)
@python_2_unicode_compatible
class DNSCryptoKey(models.Model):
"""
This model represents the cryptokeys table in the PowerDNS schema
@ -304,7 +367,16 @@ class DNSCryptoKey(models.Model):
active = models.BooleanField(default=True)
content = models.TextField()
class Meta:
verbose_name = _('DNS crypto key')
verbose_name_plural = _('DNS crypto keys')
def __str__(self):
return "{domain} {content}".format(
domain=self.domain.domain, content=self.content)
@python_2_unicode_compatible
class DNSTSIGKey(models.Model):
"""
This model represents the tsigkeys table in the PowerDNS schema specified
@ -321,11 +393,17 @@ class DNSTSIGKey(models.Model):
CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm);
"""
name = models.CharField(max_length=255)
algorithm = models.CharField(max_length=50)
algorithm = models.CharField(max_length=50, choices=DNS_TSIG_KEY_ALGORITHMS)
secret = models.CharField(max_length=255)
# check constraint is added via RunSQL in migration
class Meta:
verbose_name = _('DNS TSIG key')
verbose_name_plural = _('DNS TSIG keys')
unique_together = [
['name', 'algorithm']
]
def __str__(self):
return "{name} {algorithm} XXXX".format(
name=self.name, algorithm=self.algorithm)

View File

@ -10,9 +10,16 @@ from django.test import TestCase
from django.contrib.auth import get_user_model
from domains.models import (
DNSComment,
DNSCryptoKey,
DNSDomain,
DNSDomainMetadata,
DNSRecord,
DNSSupermaster,
DNSTSIGKey,
DomainBase,
MailDomain,
HostingDomain,
MailDomain,
)
from hostingpackages.models import (
CustomerHostingPackage,
@ -27,14 +34,14 @@ TEST_USER = 'test'
class DomainBaseTest(TestCase):
def test__str__(self):
def test___str__(self):
db = DomainBase(domain='test')
self.assertEqual(str(db), 'test')
class MailDomainTest(TestCase):
def test__str__(self):
def test___str__(self):
md = MailDomain.objects.create(domain='example.org')
self.assertEqual(str(md), 'example.org')
@ -77,8 +84,65 @@ class HostingDomainManagerTest(TestCase):
self.assertIsNotNone(hostingdomain)
self.assertTrue(hostingdomain.customer, package.customer)
class HostingDomainTest(TestCase):
def test__str__(self):
def test___str__(self):
hostingdomain = HostingDomain(domain='test')
self.assertEqual(str(hostingdomain), 'test')
class DNSDomainTest(TestCase):
def test___str__(self):
dnsdomain = DNSDomain(domain='test')
self.assertEqual(str(dnsdomain), 'test')
class DNSRecordTest(TestCase):
def test___str__(self):
dnsrecord = DNSRecord(
name='localhost', recordtype='A', content='127.0.0.1')
self.assertEqual(str(dnsrecord), 'localhost IN A 127.0.0.1')
class DNSSupermasterTest(TestCase):
def test___str__(self):
dnssupermaster = DNSSupermaster(
ip='127.0.0.1', nameserver='dns.example.org')
self.assertEqual(str(dnssupermaster), '127.0.0.1 dns.example.org')
class DNSCommentTest(TestCase):
def test___str__(self):
dnscomment = DNSComment(
name='localhost', commenttype='A', comment='good stuff')
self.assertEqual(str(dnscomment), 'localhost IN A: good stuff')
class DNSDomainMetadataTest(TestCase):
def test___str__(self):
dnsdomain = DNSDomain(domain='test')
dnsdomainmetadata = DNSDomainMetadata(
domain=dnsdomain, kind='SOA-EDIT', content='INCEPTION')
self.assertEqual(str(dnsdomainmetadata), 'test SOA-EDIT INCEPTION')
class DNSCryptoKeyTest(TestCase):
def test___str__(self):
dnsdomain = DNSDomain(domain='test')
dnscryptokey = DNSCryptoKey(domain=dnsdomain, content='testvalue')
self.assertEqual(str(dnscryptokey), 'test testvalue')
class DNSTSIGKeyTest(TestCase):
def test___str__(self):
dnstsigkey = DNSTSIGKey(
name='testkey', algorithm='hmac-md5', secret='dummykey')
self.assertEqual(str(dnstsigkey), 'testkey hmac-md5 XXXX')