feat(pxe): send uefi clients the efi loader
CI / prek (push) Successful in 11s
CI / tests (push) Successful in 42s
CI / deploy-sega (push) Successful in 10s

This commit is contained in:
ponas committed 2026-11-04 22:15:23 +01:00
1 parent 8f7e34a762
commit 284e5bd4a0
3 files changed
+32 -7

No files matched your search

+18 -1
View File
@@ -6,6 +6,15 @@ from django.utils.translation import gettext_lazy as _
from mdb.validators import validate_hostname, validate_macaddr from mdb.validators import validate_hostname, validate_macaddr
# The boot file of a PXE installable host. UEFI x86-64 clients, PXE architecture 7 or 9
# in their vendor class, get the UEFI loader instead.
PXE_FILENAME = "pxelinux.0"
PXE_EFI_FILENAME = "grubx64.efi"
PXE_EFI_CLIENT = " or ".join(
f'substring(option vendor-class-identifier, 0, 20) = "PXEClient:Arch:{arch}"'
for arch in ("00007", "00009")
)
class Nameserver(models.Model): class Nameserver(models.Model):
hostname = models.CharField(max_length=256) hostname = models.CharField(max_length=256)
@@ -250,7 +259,15 @@ class DhcpConfig(models.Model):
content += ( content += (
f"\tfixed-address {_if.host.hostname}.{_if.domain.domain_name};\n" f"\tfixed-address {_if.host.hostname}.{_if.domain.domain_name};\n"
) )
if len(_if.pxe_filename) > 0: if _if.pxe_filename == PXE_FILENAME:
content += (
f"\tif {PXE_EFI_CLIENT} {{\n"
f'\t\tfilename "{PXE_EFI_FILENAME}";\n'
"\t} else {\n"
f'\t\tfilename "{PXE_FILENAME}";\n'
"\t}\n"
)
elif _if.pxe_filename:
content += f'\tfilename "{_if.pxe_filename}";\n' content += f'\tfilename "{_if.pxe_filename}";\n'
content += "}\n" content += "}\n"
+1 -5
View File
@@ -5,7 +5,7 @@ import uuid
from django.db.models.signals import post_save, pre_delete, pre_save from django.db.models.signals import post_save, pre_delete, pre_save
from django.dispatch import receiver from django.dispatch import receiver
from mdb.models import Host, Interface, Ip4Address, Ip4Subnet, Ip6Subnet from mdb.models import PXE_FILENAME, Host, Interface, Ip4Address, Ip4Subnet, Ip6Subnet
from mdb.utils import format_domain_serial_and_add_one from mdb.utils import format_domain_serial_and_add_one
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -87,10 +87,6 @@ def update_domain_serial_when_change_to_host(sender, instance, created, **kwargs
subnet.save() subnet.save()
# The netboot host serves one menu to every machine DHCP sends to pxelinux.
PXE_FILENAME = "pxelinux.0"
@receiver(post_save, sender=Host) @receiver(post_save, sender=Host)
def set_pxe_boot_when_host_changes(sender, instance, created, **kwargs): def set_pxe_boot_when_host_changes(sender, instance, created, **kwargs):
"""An installable host netboots into the menu; unticking it stops that. """An installable host netboots into the menu; unticking it stops that.
+13 -1
View File
@@ -26,7 +26,12 @@ subnet 10.0.3.0 netmask 255.255.255.0 {
host tut { host tut {
\thardware ethernet f0:de:f1:58:be:1a; \thardware ethernet f0:de:f1:58:be:1a;
\tfixed-address tut.edb.technology; \tfixed-address tut.edb.technology;
\tfilename "pxelinux.0"; \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}
} }
""" """
@@ -99,6 +104,13 @@ def test_dhcpd_configuration_without_pxe_filename(fixtures):
assert "filename" not 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): def test_dhcpd_configuration_without_dynamic_range(fixtures):
Ip4Subnet.objects.update(dhcp_dynamic=False) Ip4Subnet.objects.update(dhcp_dynamic=False)
assert "range" not in DhcpConfig.objects.get().dhcpd_configuration() assert "range" not in DhcpConfig.objects.get().dhcpd_configuration()