2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-09-04 20:17:55 +00:00

Merge pull request #7775 from VersatusHPC/fix/anaconda-driver-disk-kernel-arg

fix(anaconda): load the driver disk that is added to the initrd
This commit is contained in:
Daniel Hilst
2026-08-31 12:12:09 -03:00
committed by GitHub
2 changed files with 224 additions and 9 deletions
+111 -9
View File
@@ -84,6 +84,42 @@ sub _centos_linux_distname
}
sub _driver_disk_marker_path
{
my $initrd = shift;
return unless defined($initrd) && length($initrd);
return "$initrd.xcat-driver-disk";
}
sub _set_driver_disk_marker
{
my ($initrd, $present) = @_;
my $marker = _driver_disk_marker_path($initrd);
return $present ? 0 : 1 unless defined($marker);
unless ($present) {
return 1 unless -e $marker;
return unlink($marker) ? 1 : 0;
}
open(my $marker_fh, '>', $marker) or return 0;
return close($marker_fh) ? 1 : 0;
}
sub _driver_disk_kernel_arg
{
my ($kversion, $initrd) = @_;
my $marker = _driver_disk_marker_path($initrd);
return '' unless defined($marker) && -f $initrd && -f $marker;
return '' if xCAT::Utils->version_cmp($kversion, "7.0") < 0;
return " inst.dd=/dd.img";
}
sub handled_commands
{
return {
@@ -1375,7 +1411,7 @@ sub mkinstall
unless ($noupdateinitrd) {
copy($kernpath, "$tftppath");
copy($initrdpath, "$tftppath/initrd.img");
&insert_dd($callback, $os, $arch, "$tftppath/initrd.img", "$tftppath/vmlinuz", $driverupdatesrc, $netdrivers, $osupdir, $ignorekernelchk);
insert_dd($callback, $os, $arch, "$tftppath/initrd.img", "$tftppath/vmlinuz", $driverupdatesrc, $netdrivers, $osupdir, $ignorekernelchk);
}
}
xCAT::MsgUtils->trace($verbose_on_off, "d", "anaconda->mkinstall: copy initrd.img and vmlinuz to $tftppath");
@@ -1536,7 +1572,9 @@ sub mkinstall
}
#TODO: dd=<url> for driver disks
$kcmdline .= _driver_disk_kernel_arg(
$kversion, "$tftppath/initrd.img"
);
if (defined($sent->{serialport})) {
unless ($sent->{serialspeed}) {
xCAT::MsgUtils->report_node_error($callback, $node, "serialport defined, but no serialspeed for this node in nodehm table");
@@ -2579,6 +2617,13 @@ sub insert_dd {
my $osupdirlist = shift;
my $ignorekernelchk = shift;
unless (_set_driver_disk_marker($img, 0)) {
my $rsp;
push @{ $rsp->{data} }, "Handle the driver update disk failed. Could not clear the initrd driver disk marker.";
xCAT::MsgUtils->message("E", $rsp, $callback);
return ();
}
my $install_dir = xCAT::TableUtils->getInstallDir();
my $cmd;
@@ -3363,12 +3408,19 @@ EOMS
if ( (&using_dracut($os)) && @dd_list) { #new style, skip the fanagling, copy over the dds and append them...
mkpath("$dd_dir/dd");
if (scalar(@dd_list) == 1) { #only one, just append it..
copy($dd_list[0], "$dd_dir/dd/dd.img");
unless (copy($dd_list[0], "$dd_dir/dd/dd.img") && -s "$dd_dir/dd/dd.img") {
my $rsp;
push @{ $rsp->{data} }, "Handle the driver update disk failed. Could not copy the driver disk.";
xCAT::MsgUtils->message("E", $rsp, $callback);
rmtree $dd_dir;
return ();
}
} elsif (scalar(@dd_list) > 1) {
unless (-x "/usr/bin/createrepo" and -x "/usr/bin/mkisofs") {
my $rsp;
push @{ $rsp->{data} }, "Merging multiple driver disks requires createrepo and mkisofs utilities";
xCAT::MsgUtils->message("E", $rsp, $callback);
rmtree $dd_dir;
return ();
}
mkpath("$dd_dir/newddimg");
@@ -3382,28 +3434,78 @@ EOMS
$repodir =~ s/\/repodata\z//;
xCAT::Utils->runcmd("createrepo $repodir", -1);
}
chdir("$dd_dir/newddimg");
unless (chdir("$dd_dir/newddimg")) {
my $rsp;
push @{ $rsp->{data} }, "Handle the driver update disk failed. Could not enter the merged driver disk directory.";
xCAT::MsgUtils->message("E", $rsp, $callback);
rmtree $dd_dir;
return ();
}
xCAT::Utils->runcmd("mkisofs -J -R -o $dd_dir/dd/dd.img .", -1);
if ($::RUNCMD_RC != 0 || !-s "$dd_dir/dd/dd.img") {
my $rsp;
push @{ $rsp->{data} }, "Handle the driver update disk failed. Could not merge the driver disks.";
xCAT::MsgUtils->message("E", $rsp, $callback);
chdir("/");
rmtree $dd_dir;
return ();
}
} else { #there should be no else...
die "This should never occur";
}
chdir($dd_dir . "/dd");
unless (chdir($dd_dir . "/dd")) {
my $rsp;
push @{ $rsp->{data} }, "Handle the driver update disk failed. Could not enter the driver disk directory.";
xCAT::MsgUtils->message("E", $rsp, $callback);
chdir("/");
rmtree $dd_dir;
return ();
}
$cmd = "find .|cpio -H newc -o|gzip -9 -c - > ../dd.gz";
xCAT::Utils->runcmd($cmd, -1);
unless (-f "../dd.gz") {
die "Error attempting to archive driver disk";
if ($::RUNCMD_RC != 0 || !-s "../dd.gz") {
my $rsp;
push @{ $rsp->{data} }, "Handle the driver update disk failed. Could not archive the driver disk.";
xCAT::MsgUtils->message("E", $rsp, $callback);
chdir("/");
rmtree $dd_dir;
return ();
}
my $ddhdl;
my $inithdl;
open($inithdl, ">>", $img);
open($ddhdl, "<", "../dd.gz");
unless (open($ddhdl, "<", "../dd.gz")) {
my $rsp;
push @{ $rsp->{data} }, "Handle the driver update disk failed. Could not append the driver disk to the initrd.";
xCAT::MsgUtils->message("E", $rsp, $callback);
chdir("/");
rmtree $dd_dir;
return ();
}
unless (open($inithdl, ">>", $img)) {
close($ddhdl);
my $rsp;
push @{ $rsp->{data} }, "Handle the driver update disk failed. Could not append the driver disk to the initrd.";
xCAT::MsgUtils->message("E", $rsp, $callback);
chdir("/");
rmtree $dd_dir;
return ();
}
binmode($ddhdl);
binmode($inithdl);
{
local $/ = \32768;
while (my $block = <$ddhdl>) { print $inithdl $block; }
}
close($ddhdl);
unless (close($inithdl) && _set_driver_disk_marker($img, 1)) {
my $rsp;
push @{ $rsp->{data} }, "Handle the driver update disk failed. Could not record the driver disk in the initrd.";
xCAT::MsgUtils->message("E", $rsp, $callback);
chdir("/");
rmtree $dd_dir;
return ();
}
chdir("/");
push @inserted_dd, @dd_list;
}
+113
View File
@@ -0,0 +1,113 @@
#!/usr/bin/env perl
use strict;
use warnings;
use Cwd qw(getcwd);
use File::Slurper qw(write_text);
use File::Spec;
use File::Temp qw(tempdir);
use FindBin;
use lib "$FindBin::Bin/../lib";
use lib "$FindBin::Bin/../../perl-xCAT";
use lib "$FindBin::Bin/../../xCAT-server/lib/perl";
use Test::More;
use XCAT::Test::File qw(repo_path);
my $plugin = repo_path('xCAT-server/lib/xcat/plugins/anaconda.pm');
plan skip_all => 'anaconda.pm not found' unless -r $plugin;
$ENV{XCATROOT} ||= repo_path('xCAT-server');
require $plugin;
my $tempdir = tempdir(CLEANUP => 1);
my $initrd = File::Spec->catfile($tempdir, 'initrd.img');
my $driver_disk = File::Spec->catfile($tempdir, 'vendor-dd.img');
write_text($initrd, "base initrd\n");
write_text($driver_disk, "driver disk\n");
my $base_size = -s $initrd;
sub insert_driver_disk {
my ($source, $fail_archive) = @_;
my $cwd = getcwd();
my @inserted;
my @messages;
{
no warnings qw(redefine once);
my $real_runcmd = \&xCAT::Utils::runcmd;
local *xCAT::TableUtils::getInstallDir = sub { return $tempdir; };
local *xCAT::MsgUtils::message = sub {
my $rsp = $_[2];
push @messages, @{ $rsp->{data} || [] };
return;
};
local *xCAT::Utils::runcmd = sub {
my ($class, $command, @arguments) = @_;
if ($fail_archive && $command =~ /cpio -H newc -o/) {
$::RUNCMD_RC = 1;
return;
}
return $real_runcmd->($class, $command, @arguments);
};
@inserted = xCAT_plugin::anaconda::insert_dd(
sub { return; },
'rhels9.6', 'x86_64', $initrd, undef,
$source, '', '', 0,
);
}
chdir($cwd) or die "Unable to restore $cwd: $!";
return ( \@inserted, \@messages );
}
my ($inserted) = insert_driver_disk("dud:$driver_disk");
is_deeply($inserted, [$driver_disk], 'insert_dd reports the driver disk it appended');
cmp_ok(-s $initrd, '>', $base_size, 'the driver disk archive is appended to the initrd');
my $marker = xCAT_plugin::anaconda::_driver_disk_marker_path($initrd);
ok(-f $marker, 'successful injection records the driver disk beside the initrd');
is(
xCAT_plugin::anaconda::_driver_disk_kernel_arg('6.10', $initrd),
'',
'anaconda before 7 continues to auto-load the embedded driver disk',
);
is(
xCAT_plugin::anaconda::_driver_disk_kernel_arg('9.6', $initrd),
' inst.dd=/dd.img',
'anaconda 7 and newer is given the inst.dd argument it reads',
);
write_text($initrd, "reused initrd\n");
is(
xCAT_plugin::anaconda::_driver_disk_kernel_arg('9.6', $initrd),
' inst.dd=/dd.img',
'a later nodeset --noupdateinitrd run reuses the persistent marker',
);
write_text($initrd, "fresh initrd\n");
my ($without_disk) = insert_driver_disk(undef);
is_deeply($without_disk, [], 'an image without a driver disk reports no insertion');
ok(!-e $marker, 'rebuilding without a driver disk clears a stale marker');
is(
xCAT_plugin::anaconda::_driver_disk_kernel_arg('9.6', $initrd),
'',
'an image without an injected driver disk receives no kernel argument',
);
my $missing_disk = File::Spec->catfile($tempdir, 'missing-dd.img');
my ($failed, $copy_messages) = insert_driver_disk("dud:$missing_disk");
is_deeply($failed, [], 'a driver disk that cannot be copied is not reported as inserted');
like(join("\n", @{$copy_messages}), qr/Could not copy the driver disk/, 'the failed copy takes the expected error path');
ok(!-e $marker, 'failed injection leaves no driver disk marker');
($inserted) = insert_driver_disk("dud:$driver_disk");
ok(-f $marker, 'the marker exists before an archive failure is exercised');
my ($archive_failed, $archive_messages) = insert_driver_disk("dud:$driver_disk", 1);
is_deeply($archive_failed, [], 'a driver disk that cannot be archived is not reported as inserted');
like(join("\n", @{$archive_messages}), qr/Could not archive the driver disk/, 'the failed archive takes the expected error path');
ok(!-e $marker, 'a failed driver disk archive leaves no marker');
ok(
xCAT_plugin::anaconda::_set_driver_disk_marker(undef, 0),
'clearing a marker for an unavailable initrd is a no-op',
);
done_testing();