143 lines
4.1 KiB
Python
143 lines
4.1 KiB
Python
"""The dhcpd.conf and reverse zones generated from the test_data fixture."""
|
|
|
|
import pytest
|
|
from django.core.management import call_command
|
|
from freezegun import freeze_time
|
|
|
|
from mdb.models import DhcpConfig, Interface, Ip4Subnet, Ip6Subnet
|
|
from mdb.services.zone_sync import ZoneSyncService
|
|
|
|
EXPECTED_DHCPD_CONF = """\
|
|
# Autogenerated configuration 2024-01-01 00:00:00
|
|
default-lease-time 600;
|
|
max-lease-time 7200;
|
|
log-facility local7;
|
|
ddns-update-style none;
|
|
|
|
# clients
|
|
subnet 10.0.3.0 netmask 255.255.255.0 {
|
|
\toption domain-name "edb.technology";
|
|
\toption domain-name-servers 158.36.190.194, 158.36.190.199, 8.8.8.8;
|
|
\toption routers 158.36.186.1;
|
|
\tdeny unknown-clients;
|
|
\trange 10.0.3.2 10.0.3.254;
|
|
}
|
|
|
|
host tut {
|
|
\thardware ethernet f0:de:f1:58:be:1a;
|
|
\tfixed-address tut.edb.technology;
|
|
\tif substring(option vendor-class-identifier, 0, 20) = "PXEClient:Arch:00007" \
|
|
or substring(option vendor-class-identifier, 0, 20) = "PXEClient:Arch:00009" {
|
|
\t\tfilename "grubx64.efi";
|
|
\t} else {
|
|
\t\tfilename "pxelinux.0";
|
|
\t}
|
|
}
|
|
"""
|
|
|
|
SOA_AND_NS = """\
|
|
$TTL 3600
|
|
@ IN SOA sega.neuf.no. sysadmin.neuf.no. (
|
|
\t{serial}\t; serial
|
|
\t28800\t; refresh
|
|
\t7200\t; retry
|
|
\t604800\t; expire
|
|
\t86400 )\t; minimum ttl
|
|
;
|
|
;
|
|
@\tIN\tNS\tsega.neuf.no.
|
|
@\tIN\tNS\tatari.neuf.no.
|
|
;
|
|
"""
|
|
|
|
EXPECTED_IP4_REVERSE = (
|
|
SOA_AND_NS.format(serial=2024010101)
|
|
+ "2 \tIN\tPTR\ttut.edb.technology.\n"
|
|
)
|
|
|
|
EXPECTED_IP6_REVERSE = (
|
|
SOA_AND_NS.format(serial=1)
|
|
+ "2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0\tPTR\ttut.edb.technology.\n"
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def fixtures(db):
|
|
# Loading the interface bumps the subnet's serial to the frozen day's first.
|
|
with freeze_time("2024-01-01 00:00:00"):
|
|
call_command("loaddata", "test_data", verbosity=0)
|
|
|
|
|
|
@pytest.fixture
|
|
def service(tmp_path):
|
|
svc = ZoneSyncService()
|
|
svc.checkzone_dir = str(tmp_path)
|
|
return svc
|
|
|
|
|
|
def body(zone_file):
|
|
"""A zone file without its header comments, which name the file and the time."""
|
|
return zone_file[zone_file.index("$TTL") :]
|
|
|
|
|
|
@freeze_time("2024-01-01 00:00:00")
|
|
def test_dhcpd_configuration(fixtures):
|
|
assert DhcpConfig.objects.get().dhcpd_configuration() == EXPECTED_DHCPD_CONF
|
|
|
|
|
|
@freeze_time("2024-01-01 00:00:00")
|
|
def test_dhcpd_configuration_authoritative(fixtures):
|
|
DhcpConfig.objects.update(authoritative=True)
|
|
conf = DhcpConfig.objects.get().dhcpd_configuration()
|
|
assert conf.splitlines()[1] == "authoritative;"
|
|
|
|
|
|
def test_dhcpd_configuration_leaves_out_non_dhcp_hosts(fixtures):
|
|
Interface.objects.update(dhcp_client=False)
|
|
assert "host tut" not in DhcpConfig.objects.get().dhcpd_configuration()
|
|
|
|
|
|
def test_dhcpd_configuration_without_pxe_filename(fixtures):
|
|
Interface.objects.update(pxe_filename="")
|
|
conf = DhcpConfig.objects.get().dhcpd_configuration()
|
|
assert "host tut {" in conf
|
|
assert "filename" not in conf
|
|
|
|
|
|
def test_dhcpd_configuration_with_custom_pxe_filename(fixtures):
|
|
Interface.objects.update(pxe_filename="custom.efi")
|
|
conf = DhcpConfig.objects.get().dhcpd_configuration()
|
|
assert '\tfilename "custom.efi";\n' in conf
|
|
assert "vendor-class-identifier" not in conf
|
|
|
|
|
|
def test_dhcpd_configuration_without_dynamic_range(fixtures):
|
|
Ip4Subnet.objects.update(dhcp_dynamic=False)
|
|
assert "range" not in DhcpConfig.objects.get().dhcpd_configuration()
|
|
|
|
|
|
def test_ip4_reverse_zone(fixtures, service):
|
|
zone = Ip4Subnet.objects.get()
|
|
contents = zone.zone_file_contents()
|
|
assert body(contents) == EXPECTED_IP4_REVERSE
|
|
status, output = service.check_zone(zone, contents)
|
|
assert status == 0, output
|
|
|
|
|
|
def test_ip4_reverse_zone_leaves_out_unassigned_addresses(fixtures):
|
|
Interface.objects.update(ip4address=None)
|
|
assert "PTR" not in Ip4Subnet.objects.get().zone_file_contents()
|
|
|
|
|
|
def test_ip6_reverse_zone(fixtures, service):
|
|
zone = Ip6Subnet.objects.get()
|
|
contents = zone.zone_file_contents()
|
|
assert body(contents) == EXPECTED_IP6_REVERSE
|
|
status, output = service.check_zone(zone, contents)
|
|
assert status == 0, output
|
|
|
|
|
|
def test_ip6_reverse_zone_name():
|
|
zone = Ip6Subnet(network="2001:16d8:eeb6:3", netmask=64)
|
|
assert zone.reverse_zone_name == "3.0.0.0.6.b.e.e.8.d.6.1.1.0.0.2.ip6.arpa"
|