feat(pxe): send uefi clients the efi loader
This commit is contained in:
3 files changed
+32
-7
No files matched your search
+18
-1
@@ -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
@@ -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.
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
Reference in new issue
Block a user