mirror of
https://github.com/xcat2/xcat-core.git
synced 2026-09-05 04:27:55 +00:00
feat(mknb): write grub2 discovery configs for riscv64
mknb only knew how to publish a discovery boot configuration for x86 (PXELINUX and xNBA) and POWER (petitboot). Any other architecture got a Genesis kernel and initramfs under /tftpboot/xcat and nothing that would make a firmware boot them, so riscv64 discovery could not start. riscv64 nodes boot through UEFI and grub2. Write one grub2 configuration per network, /tftpboot/boot/grub2/grub.cfg-<network hex prefix>, using the same network keys as the PXELINUX files. A net-booted grub2.riscv64 searches grub.cfg-01-<mac>, grub.cfg-<8 hex ip> and then shorter prefixes of the ip, so the per-node files that nodeset writes keep priority and the network file is only reached by clients without a node configuration. The file is regenerated from the published Genesis artifacts (lzma preferred over gzip), guarded by $grub_cpu so other grub2 architectures can share it later, carries the xcatd endpoint, the serial console and BOOTIF=$net_default_mac, and is dropped for networks served by a :noboot interface. It is written by name rather than into an existing file, because on a /32 network nodeset's hard link for the node carries the same name. Publishing a Genesis image now also drops the other compression variant of that architecture, so a leftover genesis.fs.<arch>.lzma can no longer be paired with a freshly published kernel by this configuration or by --configfileonly. And since these configurations are only reachable through grub2.<arch>, which xCAT does not build, a missing boot loader is reported instead of leaving the nodes to time out in firmware. xcatconfig now also runs mknb riscv64 when xCAT-genesis-base-riscv64 is installed, and the usage text lists the architecture.
This commit is contained in:
@@ -18,6 +18,14 @@ sub _canonical_genesis_arch {
|
||||
return $arch eq 'ppc64el' ? 'ppc64le' : $arch;
|
||||
}
|
||||
|
||||
# Architectures whose discovery boot goes through UEFI firmware and grub2.
|
||||
# mknb writes one grub2 configuration per network for them. The value is the
|
||||
# $grub_cpu string reported by that architecture's GRUB build, so one file can
|
||||
# carry a menu entry per architecture that shares a network.
|
||||
my %GRUB2_DISCOVERY_ARCHES = (
|
||||
riscv64 => 'riscv64',
|
||||
);
|
||||
|
||||
sub handled_commands {
|
||||
return {
|
||||
mknb => 'mknb',
|
||||
@@ -703,6 +711,9 @@ sub process_request {
|
||||
}
|
||||
} elsif ($arch =~ /ppc/) {
|
||||
mkpath("$tftpdir/pxelinux.cfg/p/");
|
||||
} elsif (exists $GRUB2_DISCOVERY_ARCHES{$arch}) {
|
||||
mkpath("$tftpdir/boot/grub2");
|
||||
chmod(0755, "$tftpdir/boot/grub2");
|
||||
}
|
||||
my $dopxe = 0;
|
||||
foreach (keys %{$normnets}) {
|
||||
@@ -816,11 +827,97 @@ sub process_request {
|
||||
print $cfgfile " initrd http://" . $xcatd_address . "$portsuffix/$initrd_file\n";
|
||||
print $cfgfile ' append "xcatd=' . $xcatd_address . ":$xcatdport $consolecmdline\"\n";
|
||||
close($cfgfile);
|
||||
} elsif (exists $GRUB2_DISCOVERY_ARCHES{$arch}) {
|
||||
# Unlike the PXELINUX files, which only look at the legacy address of the network,
|
||||
# the discovery configuration is also dropped when the xcatd address chosen for the
|
||||
# network sits on a :noboot interface: it would send Genesis to an interface that
|
||||
# must not serve booting.
|
||||
if (defined($nobootnicips{ $hexnets->{$_} }) or defined($nobootnicips{$xcatd_address})) {
|
||||
unlink("$tftpdir/boot/grub2/grub.cfg-" . uc($_));
|
||||
next;
|
||||
}
|
||||
_write_grub2_discovery_config(
|
||||
tftpdir => $tftpdir,
|
||||
hexnet => $_,
|
||||
xcatd_address => $xcatd_address,
|
||||
xcatdport => $xcatdport,
|
||||
consolecmdline => $consolecmdline,
|
||||
);
|
||||
}
|
||||
}
|
||||
if (exists $GRUB2_DISCOVERY_ARCHES{$arch} and !-e "$tftpdir/boot/grub2/grub2.$arch") {
|
||||
# The discovery configurations are only reached through this boot loader, which
|
||||
# xCAT does not build: say so instead of letting the nodes time out in firmware.
|
||||
$callback->({ data => ["Note: $tftpdir/boot/grub2/grub2.$arch is missing; $arch nodes need it to reach these configurations (it is installed by grub2-xcat, or copied from the EL $arch installation media)"] });
|
||||
}
|
||||
if ($configfileonly) {
|
||||
$callback->({ data => ["Write netboot config file done"] });
|
||||
}
|
||||
}
|
||||
|
||||
# Return the grub2-class architectures whose Genesis kernel and initrd are
|
||||
# published under $tftpdir/xcat, as [arch, grub_cpu, kernel, initrd] with the
|
||||
# file names relative to the TFTP root.
|
||||
|
||||
sub _grub2_discovery_arches {
|
||||
my ($tftpdir) = @_;
|
||||
my @present;
|
||||
foreach my $arch (sort keys %GRUB2_DISCOVERY_ARCHES) {
|
||||
next unless -e "$tftpdir/xcat/genesis.kernel.$arch";
|
||||
my ($initrd) = grep { -e "$tftpdir/$_" }
|
||||
map { "xcat/genesis.fs.$arch.$_" } qw(lzma gz);
|
||||
next unless $initrd;
|
||||
push @present,
|
||||
[ $arch, $GRUB2_DISCOVERY_ARCHES{$arch}, "xcat/genesis.kernel.$arch", $initrd ];
|
||||
}
|
||||
return @present;
|
||||
}
|
||||
|
||||
# Write the grub2 discovery configuration for one network.
|
||||
#
|
||||
# grub2.<arch>, net booted from $tftpdir/boot/grub2, looks for grub.cfg-01-<mac>,
|
||||
# then grub.cfg-<8 hex digit ip>, then ever shorter prefixes of that ip, and
|
||||
# finally grub.cfg. nodeset writes the per-node files (full ip and mac), so a
|
||||
# per-network prefix is only reached by clients without a node configuration:
|
||||
# discovery. The file is rebuilt from the Genesis artifacts present under
|
||||
# $tftpdir/xcat and removed when none are left. Returns the path written.
|
||||
sub _write_grub2_discovery_config {
|
||||
my (%args) = @_;
|
||||
my $tftpdir = $args{tftpdir};
|
||||
my $hexnet = uc($args{hexnet});
|
||||
my $cfgpath = "$tftpdir/boot/grub2/grub.cfg-$hexnet";
|
||||
my @arches = _grub2_discovery_arches($tftpdir);
|
||||
unless (@arches) {
|
||||
unlink($cfgpath);
|
||||
return;
|
||||
}
|
||||
my $cmdline = "xcatd=$args{xcatd_address}:$args{xcatdport}";
|
||||
if (defined($args{consolecmdline}) and $args{consolecmdline} ne '') {
|
||||
$cmdline .= " $args{consolecmdline}";
|
||||
}
|
||||
my $content = "# xCAT Genesis discovery for network $hexnet - generated by mknb, do not edit\n";
|
||||
$content .= "set default=0\n";
|
||||
$content .= "set timeout=5\n";
|
||||
my $keyword = 'if';
|
||||
foreach my $entry (@arches) {
|
||||
my ($arch, $grub_cpu, $kernel, $initrd) = @{$entry};
|
||||
$content .= "$keyword [ \"\$grub_cpu\" = \"$grub_cpu\" ]; then\n";
|
||||
$content .= "menuentry \"xCAT Genesis $arch\" {\n";
|
||||
$content .= " linux /$kernel $cmdline BOOTIF=\$net_default_mac\n";
|
||||
$content .= " initrd /$initrd\n";
|
||||
$content .= "}\n";
|
||||
$keyword = 'elif';
|
||||
}
|
||||
$content .= "fi\n";
|
||||
# nodeset hard-links grub.cfg-<8 hex digit ip> to the node file; on a /32 network that is
|
||||
# this file's name, so replace the name instead of truncating a shared inode.
|
||||
unlink($cfgpath);
|
||||
my $cfg;
|
||||
open($cfg, ">", $cfgpath) or return;
|
||||
print $cfg $content;
|
||||
close($cfg);
|
||||
chmod(0644, $cfgpath);
|
||||
return $cfgpath;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
Reference in New Issue
Block a user