Initial start of the context/server model, including test framework.
All checks were successful
pda-new unit tests / Run-unit-tests (push) Successful in 8s

This commit is contained in:
2025-10-20 11:22:13 +02:00
parent 14b99d7934
commit ee3d416659
10 changed files with 308 additions and 2 deletions

2
.gitignore vendored
View File

@@ -3,7 +3,7 @@
*.pot
*.pyc
__pycache__
db.sqlite3
*.sqlite3
media
staticfiles/

View File

@@ -32,6 +32,7 @@ INSTALLED_APPS = [
"django.contrib.staticfiles",
"allauth",
"allauth.account",
'pdns',
]
AUTHENTICATION_BACKENDS = [
@@ -50,6 +51,7 @@ MIDDLEWARE = [
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"django.middleware.locale.LocaleMiddleware",
"allauth.account.middleware.AccountMiddleware",
]
@@ -77,7 +79,7 @@ DEFAULT_DB = {
'ENGINE': f"django.db.backends.{DB_ENGINE}",
}
if DB_ENGINE=='sqlite3':
DEFAULT_DB['NAME'] = os.path.join('BASE_DIR',
DEFAULT_DB['NAME'] = os.path.join(BASE_DIR,
env('DB_NAME', default='pdanext.sqlite3'))
else:
DEFAULT_DB['NAME'] = env('DB_NAME')
@@ -93,6 +95,8 @@ DATABASES = {
'default': DEFAULT_DB,
}
print('Database: %s' % DATABASES['default']) if DEBUG else None
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",

2
src/pdns/__init__.py Normal file
View File

@@ -0,0 +1,2 @@
# __init__.py needs to exist or django won't load the module.

View File

@@ -0,0 +1,65 @@
# Generated by Django 5.2.5 on 2025-10-20 04:54
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = []
operations = [
migrations.CreateModel(
name="PDNSContext",
fields=[
(
"name",
models.CharField(
max_length=20,
primary_key=True,
serialize=False,
unique=True,
verbose_name="Name",
),
),
(
"description",
models.TextField(blank=True, null=True, verbose_name="Description"),
),
],
),
migrations.CreateModel(
name="PDNSServer",
fields=[
(
"name",
models.CharField(
max_length=40,
primary_key=True,
serialize=False,
unique=True,
verbose_name="Name",
),
),
(
"server_uri",
models.URLField(
help_text="Prefer IP addresses; use FQDN at your own risk.",
max_length=80,
verbose_name="Server URL",
),
),
(
"fk_network",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
related_name="servers",
to="pdns.pdnscontext",
verbose_name="Context",
),
),
],
),
]

View File

@@ -0,0 +1,34 @@
# Generated by Django 5.2.5 on 2025-10-20 07:12
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("pdns", "0001_initial"),
]
operations = [
migrations.AddField(
model_name="pdnsserver",
name="alive",
field=models.BooleanField(
default=False, editable=False, verbose_name="Alive status"
),
),
migrations.AddField(
model_name="pdnsserver",
name="last_checked",
field=models.DateTimeField(
editable=False, null=True, verbose_name="Last checked"
),
),
migrations.AddField(
model_name="pdnsserver",
name="last_seen",
field=models.DateTimeField(
editable=False, null=True, verbose_name="Last seen online"
),
),
]

View File

@@ -0,0 +1,29 @@
# Generated by Django 5.2.5 on 2025-10-20 08:20
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("pdns", "0002_pdnsserver_alive_pdnsserver_last_checked_and_more"),
]
operations = [
migrations.RenameField(
model_name="pdnsserver",
old_name="fk_network",
new_name="context",
),
migrations.RemoveField(
model_name="pdnsserver",
name="alive",
),
migrations.AddField(
model_name="pdnsserver",
name="online",
field=models.BooleanField(
default=False, editable=False, verbose_name="Online status"
),
),
]

View File

99
src/pdns/models.py Normal file
View File

@@ -0,0 +1,99 @@
#!/usr/bin/python3
#
#
from django.db import models
from django.utils.timezone import now
from django.utils.translation import gettext as _
# Okay, going to illustrate my thinking here:
# A ##Context## is a set of servers that operate together as
# authoritative for a group of zones.
# (I was going to call it a Network, but then I found out
# about https://doc.powerdns.com/authoritative/views.html )
# All ##Servers## within a Context are presumed to be
# using the same database and be otherwise interchangeable,
# Although given the limitations of some backends they can
# be set to read-only.
class PDNSContext(models.Model):
name = models.CharField(verbose_name=_('Name'),
max_length=20,
unique=True,
primary_key=True,
)
description = models.TextField(verbose_name=_('Description'),
blank=True,
null=True,
)
def __str__(self):
return self.name
def total_servers(self):
return self.servers.all().count()
def online_servers(self):
return self.servers.filter(online=True).count()
def offline_servers(self):
return self.servers.filter(online=False).count()
def status(self):
return _('Context %(name)s: %(total)d total, %(online)d online, %(offline)d offline.') % {
'name': self.name,
'total': self.total_servers(),
'online': self.online_servers(),
'offline': self.offline_servers()}
class PDNSServer(models.Model):
name = models.CharField(verbose_name=_('Name'),
max_length=40,
unique=True,
primary_key=True,
)
server_uri = models.URLField(verbose_name=_('Server URL'),
help_text='Prefer IP addresses; use FQDN at your own risk.',
max_length=80,
blank=False,
null=False
)
context=models.ForeignKey(PDNSContext,
verbose_name=_('Context'),
on_delete=models.PROTECT,
related_name='servers'
)
online = models.BooleanField(verbose_name=_('Online status'),
editable=False,
default=False
)
last_checked = models.DateTimeField(verbose_name=_('Last checked'),
editable=False,
null=True
)
last_seen = models.DateTimeField(verbose_name=_('Last seen online'),
editable=False,
null=True
)
def __str__(self):
selfstr= _("%(name)s (%(context)s): %(url)s") % { 'name': self.name,
'context': self.context.name,
'url': self.server_uri}
return selfstr
def status(self):
status = _('Online') if self.online else _('Offline')
return _('%(status)s since %(time)s') % {
'status': status,
'time': self.last_checked
}

73
src/pdns/test_models.py Normal file
View File

@@ -0,0 +1,73 @@
#!/usr/bin/python3
from django.test import TestCase
from django.utils.timezone import now
from django.utils.translation import gettext as _
from unittest import skip
from .models import (
PDNSContext,
PDNSServer
)
# Tests are run in transactions, which means that for every test_*() function
# the database restores to what's created during setUp()
class PDNSModelTestCase(TestCase):
def setUp(self):
self.test_time = now()
tc = PDNSContext.objects.create(name='test context')
PDNSServer.objects.create(name='test server',
server_uri='https://localhost:8081',
context=tc,
online=True,
last_seen=self.test_time,
last_checked=self.test_time)
self.context_target = 'test context'
self.server_target = 'test server (test context): https://localhost:8081'
self.server_status_target = _('%(status)s since %(date)s') % {
'status': _('Online'),
'date': self.test_time
}
self.server_status_offline_target = _('%(status)s since %(date)s') % {
'status': _('Offline'),
'date': self.test_time
}
return True
def test_server(self):
test_server = PDNSServer.objects.get(name='test server')
self.assertEqual(test_server.__str__(), self.server_target)
self.assertEqual(test_server.status(), self.server_status_target)
def test_server_offline(self):
test_server = PDNSServer.objects.get(name='test server')
test_server.online = False
self.assertEqual(test_server.status(), self.server_status_offline_target)
def test_context(self):
test_context = PDNSContext.objects.get(name='test context')
self.assertEqual(test_context.__str__(), self.context_target)
def test_context_onoff(self):
test_context = PDNSContext.objects.get(name='test context')
self.assertEqual(test_context.total_servers(),1)
self.assertEqual(test_context.online_servers(),1)
self.assertEqual(test_context.offline_servers(),0)
def test_context_offline(self):
test_context = PDNSContext.objects.get(name='test context')
test_server = PDNSServer.objects.get(name='test server')
test_server.online = False
test_server.save()
self.assertEqual(test_context.total_servers(),1)
self.assertEqual(test_context.online_servers(),0)
self.assertEqual(test_context.offline_servers(),1)

0
src/tests/basedata.py Normal file
View File