From 483cc22c32790cea3da34ebeebb833c52dea03d6 Mon Sep 17 00:00:00 2001 From: James Shubin Date: Sat, 18 Jan 2025 01:07:19 -0500 Subject: [PATCH] lang: core: embedded: provisioner: Add IPXE support This lets you boot from ipxe. You can run the ipxe shell from their stock image or the netboot.xyz one. For the latter, press "m", then type "dhcp" (machine is now pingable!) then type "route" to check the ip. To boot type: chain http://192.168.42.1:4280/menu.ipxe and you're off! Thanks to frebib for finding the workaround to the VFS bug. The answer is you need to run the imgfree command to unblock the initrd. --- .../embedded/provisioner/files/ipxe-menu.tmpl | 38 +++++++++++++++++++ lang/core/embedded/provisioner/main.mcl | 34 +++++++++++++++-- 2 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 lang/core/embedded/provisioner/files/ipxe-menu.tmpl diff --git a/lang/core/embedded/provisioner/files/ipxe-menu.tmpl b/lang/core/embedded/provisioner/files/ipxe-menu.tmpl new file mode 100644 index 00000000..1631f9b8 --- /dev/null +++ b/lang/core/embedded/provisioner/files/ipxe-menu.tmpl @@ -0,0 +1,38 @@ +#!ipxe + +menu iPXE Boot Options + +item kickstart Install {{ .distro }} {{ .version }} {{ .arch }} ( kickstart ) +item manual Install {{ .distro }} {{ .version }} {{ .arch }} ( manual ) +item shell iPXE shell +item exit Exit to BIOS + +choose --default kickstart --timeout 10000 option && goto ${option} + +:kickstartwip +imgfree +set server_root {{ .server_base }} +kernel ${server_root}{{ .distro }}{{ .version }}-{{ .arch }}/vmlinuz ip=dhcp initrd=initrd.magic inst.repo={{ .inst_repo_base }}releases/{{ .version }}/{{ .flavour }}/{{ .arch }}/os/ inst.text inst.ks={{ .ks }} console=ttyS1,115200n8 +initrd ${server_root}{{ .distro }}{{ .version }}-{{ .arch }}/initrd.img +boot + +# The imgfree command works around some bug, which makes our initrd not be seen +# properly. We would otherwise get a VFS not syncing error on boot. + +:kickstart +imgfree +kernel {{ .server_base }}{{ .distro }}{{ .version }}-{{ .arch }}/vmlinuz ip=dhcp initrd=initrd.img inst.repo={{ .inst_repo_base }}releases/{{ .version }}/{{ .flavour }}/{{ .arch }}/os/ inst.ks={{ .ks }} +initrd {{ .server_base }}{{ .distro }}{{ .version }}-{{ .arch }}/initrd.img +boot + +:manual +imgfree +kernel {{ .server_base }}{{ .distro }}{{ .version }}-{{ .arch }}/vmlinuz ip=dhcp inst.repo={{ .inst_repo_base }}releases/{{ .version }}/{{ .flavour }}/{{ .arch }}/os/ +initrd {{ .server_base }}{{ .distro }}{{ .version }}-{{ .arch }}/initrd.img +boot + +:shell +shell + +:exit +exit diff --git a/lang/core/embedded/provisioner/main.mcl b/lang/core/embedded/provisioner/main.mcl index c1c19ef9..eb98952c 100644 --- a/lang/core/embedded/provisioner/main.mcl +++ b/lang/core/embedded/provisioner/main.mcl @@ -80,6 +80,7 @@ class base($config) { # eg: equivalent of: https://download.fedoraproject.org/pub/fedora/linux/ $inst_repo_base = "http://${router_ip}:${http_port_str}/fedora/" # private lan online, no https! + $server_base = "http://${router_ip}:${http_port_str}/" # private lan online, no https! $syslinux_root = "/usr/share/syslinux/" @@ -360,11 +361,17 @@ class base:repo($config) { $uefi_root = "${uefi_extract_dir}/boot/efi/EFI/fedora/" $uefi_shim = "${uefi_root}shim.efi" + $uefi_shimx64 = "${uefi_root}shimx64.efi" tftp:file "/uefi/shim.efi" { # needs leading slash path => $uefi_shim, # TODO: add autoedges Depend => Exec["uefi-extract-${uid}"], } + tftp:file "/uefi/shimx64.efi" { # needs leading slash + path => $uefi_shimx64, # TODO: add autoedges + + Depend => Exec["uefi-extract-${uid}"], + } tftp:file "/uefi/grubx64.efi" { # sometimes used? path => "${uefi_root}grubx64.efi", # TODO: add autoedges @@ -399,6 +406,11 @@ class base:repo($config) { #Depend => Pkg[$pkgs], } + http:file "/${uid}/vmlinuz" { # when using ipxe + path => $vmlinuz_file, # TODO: add autoedges + + #Depend => Pkg[$pkgs], + } $initrd_file = "${distroarch_tftp_prefix}initrd.img" exec "initrd-${uid}" { @@ -421,6 +433,11 @@ class base:repo($config) { #Depend => Pkg[$pkgs], } + http:file "/${uid}/initrd.img" { # when using ipxe + path => $initrd_file, # TODO: add autoedges + + #Depend => Pkg[$pkgs], + } # this file resource serves the entire rsync directory over http if $mirror == "" { # and $rsync != "" @@ -626,7 +643,7 @@ class base:host($name, $config) { } } - $tftp_menu_template = struct{ + $menu_template = struct{ distro => $distro, version => $version, # 39 for fedora 39 arch => $arch, # could also be aarch64 @@ -634,6 +651,7 @@ class base:host($name, $config) { ks => "http://${router_ip}:${http_port_str}/fedora/kickstart/${hkey}.ks", # usually $mac or `default` inst_repo_base => $inst_repo_base, + server_base => $server_base, } # @@ -661,20 +679,30 @@ class base:host($name, $config) { "/uefi/grub.cfg-01-${old_mac}" } + $ipxe_menu = if $mac == "" { + "menu.ipxe" + } else { + "${old_mac}.ipxe" + } + if $bios { tftp:file "${bios_menu}" { # for bios - data => golang.template(deploy.readfile("/files/bios-menu.tmpl"), $tftp_menu_template), + data => golang.template(deploy.readfile("/files/bios-menu.tmpl"), $menu_template), } } else { tftp:file "${uefi_menu}" { # for uefi # XXX: linuxefi & initrdefi VS. kernel & append ? - data => golang.template(deploy.readfile("/files/uefi-menu.tmpl"), $tftp_menu_template), + data => golang.template(deploy.readfile("/files/uefi-menu.tmpl"), $menu_template), #Depend => Pkg[$pkgs_uefi], #Depend => Exec["uefi-extract"], } } + http:file "/${ipxe_menu}" { # for ipxe + data => golang.template(deploy.readfile("/files/ipxe-menu.tmpl"), $menu_template), + } + # If it's a dir we don't need a suffix, otherwise return the last chunk. $handoff_code_chunk = if strings.has_suffix($prefix, "/") { ""